From 6e848b250b4cde98fb9a40b17421f1f54eacd8f3 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Tue, 21 May 2024 02:18:34 +0200 Subject: [PATCH] cmd, pkg/nvidia: Enable the proprietary NVIDIA driver This uses the NVIDIA Container Toolkit [1] to generate a Container Device Interface specification [2] on the host during the 'enter' and 'run' commands. The specification is saved as JSON in the runtime directories at /run/toolbox or $XDG_RUNTIME_DIR/toolbox to make it available to the Toolbx container's entry point. The environment variables in the specification are directly passed to 'podman exec', while the hooks and mounts are handled by the entry point. Toolbx containers already have access to all the devices in the host operating system's /dev, and containers share the kernel space driver with the host. So, this is only about making the user space driver available to the container. It's done by bind mounting the files mentioned in the generated CDI specification from the host to the container, and then updating the container's dynamic linker cache. This neither depends on 'nvidia-ctk cdi generate' to generate the Container Device Interface specification nor on 'podman create --device' to consume it. The main problem with nvidia-ctk and 'podman create' is that the specification must be saved in /etc/cdi or /var/run/cdi, both of which require root access, for it to be visible to 'podman create --device'. Toolbx containers are often used rootless, so requiring root privileges for hardware support, something that's not necessary on the host, will be a problem. Secondly, updating the toolbox(1) binary won't let existing containers use the proprietary NVIDIA driver, because 'podman create' only affects new containers. Therefore, toolbox(1) uses the Go APIs used by 'nvidia-ctk cdi generate' and 'podman create --device' to generate, save, load and apply the CDI specification itself. This removes the need for root privileges due to /etc/cdi or /var/run/cdi, and makes the driver available to existing containers. Until Bats 1.10.0, 'run --keep-empty-lines' had a bug where it counted the trailing newline on the last line as a separate line [3]. However, Bats 1.10.0 is only available in Fedora >= 39 and is absent from Fedora 38. Based on an idea from Ievgen Popovych. [1] https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/ https://github.com/NVIDIA/nvidia-container-toolkit [2] https://github.com/cncf-tags/container-device-interface [3] Bats commit 6648e2143bffb933 https://github.com/bats-core/bats-core/commit/6648e2143bffb933 https://github.com/bats-core/bats-core/issues/708 https://github.com/containers/toolbox/issues/116 --- src/cmd/initContainer.go | 188 ++++++++++- src/cmd/root.go | 2 + src/cmd/run.go | 65 +++- src/cmd/utils.go | 12 + src/go.mod | 15 +- src/go.sum | 53 +++- src/meson.build | 1 + src/pkg/nvidia/nvidia.go | 103 ++++++ test/system/230-cdi.bats | 468 ++++++++++++++++++++++++++++ test/system/data/cdi-empty.json | 2 + test/system/data/cdi-hooks-00.json | 15 + test/system/data/cdi-hooks-01.json | 17 + test/system/data/cdi-hooks-02.json | 19 ++ test/system/data/cdi-hooks-10.json | 15 + test/system/data/cdi-hooks-11.json | 15 + test/system/data/cdi-hooks-12.json | 15 + test/system/data/cdi-hooks-13.json | 15 + test/system/data/cdi-hooks-14.json | 15 + test/system/data/cdi-hooks-15.json | 15 + test/system/data/cdi-mounts-10.json | 10 + test/system/data/cdi-mounts-11.json | 10 + test/system/data/cdi-mounts-12.json | 10 + test/system/meson.build | 1 + 23 files changed, 1070 insertions(+), 11 deletions(-) create mode 100644 src/pkg/nvidia/nvidia.go create mode 100644 test/system/230-cdi.bats create mode 100644 test/system/data/cdi-empty.json create mode 100644 test/system/data/cdi-hooks-00.json create mode 100644 test/system/data/cdi-hooks-01.json create mode 100644 test/system/data/cdi-hooks-02.json create mode 100644 test/system/data/cdi-hooks-10.json create mode 100644 test/system/data/cdi-hooks-11.json create mode 100644 test/system/data/cdi-hooks-12.json create mode 100644 test/system/data/cdi-hooks-13.json create mode 100644 test/system/data/cdi-hooks-14.json create mode 100644 test/system/data/cdi-hooks-15.json create mode 100644 test/system/data/cdi-mounts-10.json create mode 100644 test/system/data/cdi-mounts-11.json create mode 100644 test/system/data/cdi-mounts-12.json diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index 4be931f47..de7bcfcc5 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -30,9 +30,12 @@ import ( "github.com/containers/toolbox/pkg/shell" "github.com/containers/toolbox/pkg/utils" "github.com/fsnotify/fsnotify" + "github.com/google/renameio/v2" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "golang.org/x/sys/unix" + "tags.cncf.io/container-device-interface/pkg/cdi" + "tags.cncf.io/container-device-interface/specs-go" ) var ( @@ -264,6 +267,36 @@ func initContainer(cmd *cobra.Command, args []string) error { return err } + uidString := strconv.Itoa(initContainerFlags.uid) + targetUser, err := user.LookupId(uidString) + if err != nil { + return fmt.Errorf("failed to look up user ID %s: %w", uidString, err) + } + + cdiFileForNvidia, err := getCDIFileForNvidia(targetUser) + if err != nil { + return err + } + + logrus.Debugf("Loading Container Device Interface for NVIDIA from file %s", cdiFileForNvidia) + + cdiSpecForNvidia, err := loadCDISpecFrom(cdiFileForNvidia) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + logrus.Debugf("Loading Container Device Interface for NVIDIA: file %s not found", + cdiFileForNvidia) + } else { + logrus.Debugf("Loading Container Device Interface for NVIDIA: failed: %s", err) + return errors.New("failed to load Container Device Interface for NVIDIA") + } + } + + if cdiSpecForNvidia != nil { + if err := applyCDISpecForNvidia(cdiSpecForNvidia); err != nil { + return err + } + } + if utils.PathExists("/etc/krb5.conf.d") && !utils.PathExists("/etc/krb5.conf.d/kcm_default_ccache") { logrus.Debug("Setting KCM as the default Kerberos credential cache") @@ -338,12 +371,6 @@ func initContainer(cmd *cobra.Command, args []string) error { logrus.Debug("Finished initializing container") - uidString := strconv.Itoa(initContainerFlags.uid) - targetUser, err := user.LookupId(uidString) - if err != nil { - return fmt.Errorf("failed to look up user ID %s: %w", uidString, err) - } - toolboxRuntimeDirectory, err := utils.GetRuntimeDirectory(targetUser) if err != nil { return err @@ -404,6 +431,83 @@ func initContainerHelp(cmd *cobra.Command, args []string) { } } +func applyCDISpecForNvidia(spec *specs.Spec) error { + if spec == nil { + panic("spec not specified") + } + + logrus.Debug("Applying Container Device Interface for NVIDIA") + + for _, mount := range spec.ContainerEdits.Mounts { + if err := (&cdi.Mount{Mount: mount}).Validate(); err != nil { + logrus.Debugf("Applying Container Device Interface for NVIDIA: invalid mount: %s", err) + return errors.New("invalid mount in Container Device Interface for NVIDIA") + } + + if mount.Type == "" { + mount.Type = "bind" + } + + if mount.Type != "bind" { + logrus.Debugf("Applying Container Device Interface for NVIDIA: unknown mount type %s", + mount.Type) + continue + } + + flags := strings.Join(mount.Options, ",") + hostPath := filepath.Join(string(filepath.Separator), "run", "host", mount.HostPath) + if err := mountBind(mount.ContainerPath, hostPath, flags); err != nil { + logrus.Debugf("Applying Container Device Interface for NVIDIA: %s", err) + return errors.New("failed to apply mount from Container Device Interface for NVIDIA") + } + } + + for _, hook := range spec.ContainerEdits.Hooks { + if err := (&cdi.Hook{Hook: hook}).Validate(); err != nil { + logrus.Debugf("Applying Container Device Interface for NVIDIA: invalid hook: %s", err) + return errors.New("invalid hook in Container Device Interface for NVIDIA") + } + + if hook.HookName != cdi.CreateContainerHook { + logrus.Debugf("Applying Container Device Interface for NVIDIA: unknown hook name %s", + hook.HookName) + continue + } + + if len(hook.Args) < 3 || + hook.Args[0] != "nvidia-ctk" || + hook.Args[1] != "hook" || + hook.Args[2] != "update-ldcache" { + logrus.Debugf("Applying Container Device Interface for NVIDIA: unknown hook arguments") + continue + } + + var folderFlag bool + var folders []string + hookArgs := hook.Args[3:] + + for _, hookArg := range hookArgs { + if hookArg == "--folder" { + folderFlag = true + continue + } + + if folderFlag { + folders = append(folders, hookArg) + } + + folderFlag = false + } + + if err := ldConfig("toolbx-nvidia.conf", folders); err != nil { + logrus.Debugf("Applying Container Device Interface for NVIDIA: %s", err) + return errors.New("failed to update ldcache for Container Device Interface for NVIDIA") + } + } + + return nil +} + func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShell string, homeLink bool) error { if homeLink { if err := redirectPath("/home", "/var/home", true); err != nil { @@ -517,6 +621,73 @@ func handleFileSystemEvent(event fsnotify.Event) { } } +func ldConfig(configFileBase string, dirs []string) error { + logrus.Debug("Updating dynamic linker cache") + + var args []string + + if !utils.PathExists("/etc/ld.so.cache") { + logrus.Debug("Updating dynamic linker cache: no /etc/ld.so.cache found") + args = append(args, "-N") + } + + if utils.PathExists("/etc/ld.so.conf.d") { + if len(dirs) > 0 { + var builder strings.Builder + builder.WriteString("# Written by Toolbx\n") + builder.WriteString("# https://containertoolbx.org/\n") + builder.WriteString("\n") + + configured := make(map[string]struct{}) + + for _, dir := range dirs { + if _, ok := configured[dir]; ok { + continue + } + + configured[dir] = struct{}{} + builder.WriteString(dir) + builder.WriteString("\n") + } + + dirConfigString := builder.String() + dirConfigBytes := []byte(dirConfigString) + configFile := filepath.Join("/etc/ld.so.conf.d", configFileBase) + if err := renameio.WriteFile(configFile, dirConfigBytes, 0644); err != nil { + logrus.Debugf("Updating dynamic linker cache: failed to update configuration: %s", err) + return errors.New("failed to update dynamic linker cache configuration") + } + } + } else { + logrus.Debug("Updating dynamic linker cache: no /etc/ld.so.conf.d found") + args = append(args, dirs...) + } + + if err := shell.Run("ldconfig", nil, nil, nil, args...); err != nil { + logrus.Debugf("Updating dynamic linker cache: failed: %s", err) + return errors.New("failed to update dynamic linker cache") + } + + return nil +} + +func loadCDISpecFrom(path string) (*specs.Spec, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + spec, err := cdi.ParseSpec(data) + if err != nil { + return nil, err + } + if spec == nil { + return nil, errors.New("missing data") + } + + return spec, nil +} + func mountBind(containerPath, source, flags string) error { fi, err := os.Stat(source) if err != nil { @@ -537,6 +708,11 @@ func mountBind(containerPath, source, flags string) error { } else if fileMode.IsRegular() { logrus.Debugf("Creating regular file %s", containerPath) + containerPathDir := filepath.Dir(containerPath) + if err := os.MkdirAll(containerPathDir, 0755); err != nil { + return fmt.Errorf("failed to create directory %s: %w", containerPathDir, err) + } + containerPathFile, err := os.Create(containerPath) if err != nil && !os.IsExist(err) { return fmt.Errorf("failed to create regular file %s: %w", containerPath, err) diff --git a/src/cmd/root.go b/src/cmd/root.go index 65341f43d..75004b7b9 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -26,6 +26,7 @@ import ( "strings" "syscall" + "github.com/containers/toolbox/pkg/nvidia" "github.com/containers/toolbox/pkg/podman" "github.com/containers/toolbox/pkg/utils" "github.com/containers/toolbox/pkg/version" @@ -382,6 +383,7 @@ func setUpLoggers() error { logrus.SetLevel(logLevel) if rootFlags.verbose > 1 { + nvidia.SetLogLevel(logLevel) rootFlags.logPodman = true } diff --git a/src/cmd/run.go b/src/cmd/run.go index 355a524d2..85d90bcbe 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -19,6 +19,7 @@ package cmd import ( "bufio" "context" + "encoding/json" "errors" "fmt" "io" @@ -28,15 +29,18 @@ import ( "strings" "time" + "github.com/containers/toolbox/pkg/nvidia" "github.com/containers/toolbox/pkg/podman" "github.com/containers/toolbox/pkg/shell" "github.com/containers/toolbox/pkg/term" "github.com/containers/toolbox/pkg/utils" "github.com/fsnotify/fsnotify" "github.com/go-logfmt/logfmt" + "github.com/google/renameio/v2" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "golang.org/x/sys/unix" + "tags.cncf.io/container-device-interface/specs-go" ) type collectEntryPointErrorFunc func(err error) @@ -273,9 +277,31 @@ func runCommand(container string, return err } + var cdiEnviron []string + + cdiSpecForNvidia, err := nvidia.GenerateCDISpec() + if err != nil { + if !errors.Is(err, nvidia.ErrPlatformUnsupported) { + return err + } + } else { + cdiEnviron = append(cdiEnviron, cdiSpecForNvidia.ContainerEdits.Env...) + } + startContainerTimestamp := time.Unix(-1, 0) if entryPointPID <= 0 { + if cdiSpecForNvidia != nil { + cdiFileForNvidia, err := getCDIFileForNvidia(currentUser) + if err != nil { + return err + } + + if err := saveCDISpecTo(cdiSpecForNvidia, cdiFileForNvidia); err != nil { + return err + } + } + startContainerTimestamp = time.Now() logrus.Debugf("Starting container %s", container) @@ -317,6 +343,7 @@ func runCommand(container string, if err := runCommandWithFallbacks(container, preserveFDs, command, + cdiEnviron, emitEscapeSequence, fallbackToBash); err != nil { return err @@ -327,7 +354,7 @@ func runCommand(container string, func runCommandWithFallbacks(container string, preserveFDs uint, - command []string, + command, environ []string, emitEscapeSequence, fallbackToBash bool) error { logrus.Debug("Checking if 'podman exec' supports disabling the detach keys") @@ -340,6 +367,12 @@ func runCommandWithFallbacks(container string, } envOptions := utils.GetEnvOptionsForPreservedVariables() + for _, env := range environ { + logrus.Debugf("%s", env) + envOption := "--env=" + env + envOptions = append(envOptions, envOption) + } + preserveFDsString := fmt.Sprint(preserveFDs) var stderr io.Writer @@ -828,6 +861,36 @@ func isUsePollingSet() bool { return true } +func saveCDISpecTo(spec *specs.Spec, path string) error { + if path == "" { + panic("path not specified") + } + + if spec == nil { + panic("spec not specified") + } + + logrus.Debugf("Saving Container Device Interface to file %s", path) + + if extension := filepath.Ext(path); extension != ".json" { + panicMsg := fmt.Sprintf("path has invalid extension %s", extension) + panic(panicMsg) + } + + data, err := json.MarshalIndent(spec, "", " ") + if err != nil { + logrus.Debugf("Saving Container Device Interface: failed to marshal JSON: %s", err) + return errors.New("failed to marshal Container Device Interface to JSON") + } + + if err := renameio.WriteFile(path, data, 0644); err != nil { + logrus.Debugf("Saving Container Device Interface: failed to write file: %s", err) + return errors.New("failed to write Container Device Interface to file") + } + + return nil +} + func showEntryPointLog(line string) error { var logLevel logrus.Level var logLevelFound bool diff --git a/src/cmd/utils.go b/src/cmd/utils.go index 9fda02aeb..c5c35235a 100644 --- a/src/cmd/utils.go +++ b/src/cmd/utils.go @@ -26,6 +26,8 @@ import ( "io" "os" "os/exec" + "os/user" + "path/filepath" "strings" "syscall" @@ -329,6 +331,16 @@ func createErrorInvalidRelease(hint string) error { return errors.New(errMsg) } +func getCDIFileForNvidia(targetUser *user.User) (string, error) { + toolboxRuntimeDirectory, err := utils.GetRuntimeDirectory(targetUser) + if err != nil { + return "", err + } + + cdiFile := filepath.Join(toolboxRuntimeDirectory, "cdi-nvidia.json") + return cdiFile, nil +} + func getUsageForCommonCommands() string { var builder strings.Builder fmt.Fprintf(&builder, "create Create a new Toolbx container\n") diff --git a/src/go.mod b/src/go.mod index 10faa9fe8..4a2eddef6 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,37 +4,50 @@ go 1.20 require ( github.com/HarryMichal/go-version v1.0.1 + github.com/NVIDIA/go-nvlib v0.2.0 + github.com/NVIDIA/nvidia-container-toolkit v1.15.0 github.com/acobaugh/osrelease v0.1.0 github.com/briandowns/spinner v1.18.0 github.com/docker/go-units v0.5.0 github.com/fsnotify/fsnotify v1.7.0 github.com/go-logfmt/logfmt v0.5.0 github.com/godbus/dbus/v5 v5.0.6 + github.com/google/renameio/v2 v2.0.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.3.0 github.com/spf13/viper v1.10.1 github.com/stretchr/testify v1.9.0 golang.org/x/sys v0.19.0 + tags.cncf.io/container-device-interface v0.7.1 + tags.cncf.io/container-device-interface/specs-go v0.7.0 ) require ( + github.com/NVIDIA/go-nvml v0.12.0-3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.13.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/text v0.3.8 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/src/go.sum b/src/go.sum index 58d194020..a78d37e4a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -51,6 +51,12 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/HarryMichal/go-version v1.0.1 h1:Vgk1dPyHckkoUu0AED900+yO43+uwDuiNPsdpYe63KE= github.com/HarryMichal/go-version v1.0.1/go.mod h1:UNoJ+GvCcmwu0F9Mu1u5y56lP5rWksgkiwLlGx3r+Pk= +github.com/NVIDIA/go-nvlib v0.2.0 h1:roq+SDstbP1fcy2XVH7wB2Gz2/Ud7Q+NGQYOcVITVrA= +github.com/NVIDIA/go-nvlib v0.2.0/go.mod h1:kFuLNTyD1tF6FbRFlk+/EdUW5BrkE+v1Y3A3/9zKSjA= +github.com/NVIDIA/go-nvml v0.12.0-3 h1:QwfjYxEqIQVRhl8327g2Y3ZvKResPydpGSKtCIIK9jE= +github.com/NVIDIA/go-nvml v0.12.0-3/go.mod h1:SOufGc5Wql+cxrIZ8RyJwVKDYxfbs4WPkHXqadcbfvA= +github.com/NVIDIA/nvidia-container-toolkit v1.15.0 h1:YmYZUKJzhz/lJSVH6k1mk5IUCHpt8HwRtwMrtBoCzhQ= +github.com/NVIDIA/nvidia-container-toolkit v1.15.0/go.mod h1:SUwxfwi+dl1LtVlpAnJEolxuZfCtAVmOKRGWhJYsiJI= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE= github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= @@ -68,6 +74,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -199,7 +207,12 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= +github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -208,6 +221,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -218,6 +232,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -254,8 +270,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -287,16 +303,26 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= @@ -318,12 +344,15 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -353,7 +382,16 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -419,6 +457,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -508,6 +548,7 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -775,8 +816,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -802,3 +843,9 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +tags.cncf.io/container-device-interface v0.7.1 h1:MATNCbAD1su9U6zwQe5BrQ2vGGp1GBayD70bYaxYCNE= +tags.cncf.io/container-device-interface v0.7.1/go.mod h1:h1JVuOqTQVORp8DziaWKUCDNzAmN+zeCbqbqD30D0ZQ= +tags.cncf.io/container-device-interface/specs-go v0.7.0 h1:w/maMGVeLP6TIQJVYT5pbqTi8SCw/iHZ+n4ignuGHqg= +tags.cncf.io/container-device-interface/specs-go v0.7.0/go.mod h1:hMAwAbMZyBLdmYqWgYcKH0F/yctNpV3P35f+/088A80= diff --git a/src/meson.build b/src/meson.build index 025fc94f6..3a0a50001 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,6 +20,7 @@ sources = files( 'cmd/root_test.go', 'cmd/run.go', 'cmd/utils.go', + 'pkg/nvidia/nvidia.go', 'pkg/podman/container.go', 'pkg/podman/errors.go', 'pkg/podman/podman.go', diff --git a/src/pkg/nvidia/nvidia.go b/src/pkg/nvidia/nvidia.go new file mode 100644 index 000000000..a707ff776 --- /dev/null +++ b/src/pkg/nvidia/nvidia.go @@ -0,0 +1,103 @@ +/* + * Copyright © 2024 Red Hat Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package nvidia + +import ( + "errors" + "io" + + "github.com/NVIDIA/go-nvlib/pkg/nvlib/info" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi" + nvspec "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec" + "github.com/sirupsen/logrus" + "tags.cncf.io/container-device-interface/specs-go" +) + +var ( + logLevel = logrus.ErrorLevel +) + +var ( + ErrPlatformUnsupported = errors.New("platform is unsupported") +) + +func createNullLogger() *logrus.Logger { + null := logrus.New() + null.SetLevel(logrus.PanicLevel) + null.SetOutput(io.Discard) + return null +} + +func GenerateCDISpec() (*specs.Spec, error) { + logrus.Debugf("Generating Container Device Interface for NVIDIA") + + info := info.New() + + if ok, reason := info.HasDXCore(); ok { + logrus.Debugf("Generating Container Device Interface for NVIDIA: Windows is unsupported: %s", reason) + return nil, ErrPlatformUnsupported + } + + hasNvml, reason := info.HasNvml() + if !hasNvml { + logrus.Debugf("Generating Container Device Interface for NVIDIA: NVML not found: %s", reason) + } + + isTegra, reason := info.IsTegraSystem() + if !isTegra { + logrus.Debugf("Generating Container Device Interface for NVIDIA: not a Tegra system: %s", reason) + } + + if !hasNvml && !isTegra { + logrus.Debug("Generating Container Device Interface for NVIDIA: skipping") + return nil, ErrPlatformUnsupported + } + + var logger *logrus.Logger + if logLevel < logrus.DebugLevel { + logger = createNullLogger() + } else { + logger = logrus.StandardLogger() + } + + cdi, err := nvcdi.New(nvcdi.WithLogger(logger)) + if err != nil { + logrus.Debugf("Generating Container Device Interface for NVIDIA: failed to create library: %s", err) + return nil, errors.New("failed to create Container Device Interface library for NVIDIA") + } + + commonEdits, err := cdi.GetCommonEdits() + if err != nil { + logrus.Debugf("Generating Container Device Interface for NVIDIA: failed to get containerEdits: %s", err) + return nil, errors.New("failed to get Container Device Interface containerEdits for NVIDIA") + } + + spec, err := nvspec.New(nvspec.WithEdits(*commonEdits.ContainerEdits)) + if err != nil { + logrus.Debugf("Generating Container Device Interface for NVIDIA: failed to generate: %s", err) + return nil, errors.New("failed to generate Container Device Interface for NVIDIA") + } + + specRaw := spec.Raw() + logrus.Debugf("Generated Container Device Interface for NVIDIA with version %s", specRaw.Version) + + return specRaw, nil +} + +func SetLogLevel(level logrus.Level) { + logLevel = level +} diff --git a/test/system/230-cdi.bats b/test/system/230-cdi.bats new file mode 100644 index 000000000..7a6ddbee9 --- /dev/null +++ b/test/system/230-cdi.bats @@ -0,0 +1,468 @@ +# shellcheck shell=bats +# +# Copyright © 2024 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load 'libs/bats-support/load' +load 'libs/bats-assert/load' +load 'libs/helpers' + +setup() { + bats_require_minimum_version 1.7.0 + _setup_environment + cleanup_containers + pushd "$HOME" || return 1 + rm --force "$XDG_RUNTIME_DIR/toolbox/cdi-nvidia.json" || return 1 +} + +teardown() { + rm --force "$XDG_RUNTIME_DIR/toolbox/cdi-nvidia.json" || return 1 + popd || return 1 + cleanup_containers +} + +@test "cdi: Smoke test" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-empty.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-empty.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test /etc/ld.so.cache -ot "$toolbx_runtime_directory/cdi-nvidia.json" + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: ldconfig(8) with no folder" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-00.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test "$toolbx_runtime_directory/cdi-nvidia.json" -ot /etc/ld.so.cache + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-00.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: ldconfig(8) with one folder" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-01.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test "$toolbx_runtime_directory/cdi-nvidia.json" -ot /etc/ld.so.cache + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-01.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run cat /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_success + assert_line --index 0 "# Written by Toolbx" + assert_line --index 1 "# https://containertoolbx.org/" + assert_line --index 2 "" + assert_line --index 3 "/usr/lib64" + + if check_bats_version 1.10.0; then + assert [ ${#lines[@]} -eq 4 ] + else + assert [ ${#lines[@]} -eq 5 ] + fi + + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: ldconfig(8) with two folders" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-02.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test "$toolbx_runtime_directory/cdi-nvidia.json" -ot /etc/ld.so.cache + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-02.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run cat /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_success + assert_line --index 0 "# Written by Toolbx" + assert_line --index 1 "# https://containertoolbx.org/" + assert_line --index 2 "" + assert_line --index 3 "/usr/lib" + assert_line --index 4 "/usr/lib64" + + if check_bats_version 1.10.0; then + assert [ ${#lines[@]} -eq 5 ] + else + assert [ ${#lines[@]} -eq 6 ] + fi + + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: Try invalid JSON" { + local invalid_json="This is not JSON" + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + echo "$invalid_json" >"$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if grep --invert-match --quiet --no-messages "^$invalid_json$" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to load Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try an empty file" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + touch "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if [ -s "$toolbx_runtime_directory/cdi-nvidia.json" ]; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to load Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try hook with invalid path" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-10.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-10.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: invalid hook in Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try hook with unknown path" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-11.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test /etc/ld.so.cache -ot "$toolbx_runtime_directory/cdi-nvidia.json" + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-11.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: Try hook with unknown args (a)" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-12.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test /etc/ld.so.cache -ot "$toolbx_runtime_directory/cdi-nvidia.json" + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-12.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: Try hook with unknown args (b)" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-13.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test /etc/ld.so.cache -ot "$toolbx_runtime_directory/cdi-nvidia.json" + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-13.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: Try hook with invalid name" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-14.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-14.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: invalid hook in Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try hook with unknown name" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-hooks-15.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run \ + test /etc/ld.so.cache -ot "$toolbx_runtime_directory/cdi-nvidia.json" + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-hooks-15.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /etc/ld.so.conf.d/toolbx-nvidia.conf + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "cdi: Try mount with invalid container path" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-mounts-10.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-mounts-10.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: invalid mount in Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try mount with invalid host path" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-mounts-11.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-mounts-11.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: invalid mount in Container Device Interface for NVIDIA" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "cdi: Try mount with non-existent paths" { + local toolbx_runtime_directory="$XDG_RUNTIME_DIR/toolbox" + + create_default_container + + # shellcheck disable=SC2174 + mkdir --mode 700 --parents "$toolbx_runtime_directory" + + cp "$BATS_TEST_DIRNAME/data/cdi-mounts-12.json" "$toolbx_runtime_directory/cdi-nvidia.json" + chmod 644 "$toolbx_runtime_directory/cdi-nvidia.json" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run true + + if ! cmp --silent "$BATS_TEST_DIRNAME/data/cdi-mounts-12.json" "$toolbx_runtime_directory/cdi-nvidia.json"; then + skip "found NVIDIA hardware" + fi + + assert_success + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run --keep-empty-lines --separate-stderr "$TOOLBX" run test -e /non/existent/path + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} diff --git a/test/system/data/cdi-empty.json b/test/system/data/cdi-empty.json new file mode 100644 index 000000000..2c63c0851 --- /dev/null +++ b/test/system/data/cdi-empty.json @@ -0,0 +1,2 @@ +{ +} diff --git a/test/system/data/cdi-hooks-00.json b/test/system/data/cdi-hooks-00.json new file mode 100644 index 000000000..f937e38d0 --- /dev/null +++ b/test/system/data/cdi-hooks-00.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache" + ], + "hookName": "createContainer", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-01.json b/test/system/data/cdi-hooks-01.json new file mode 100644 index 000000000..d8061bf41 --- /dev/null +++ b/test/system/data/cdi-hooks-01.json @@ -0,0 +1,17 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache", + "--folder", + "/usr/lib64" + ], + "hookName": "createContainer", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-02.json b/test/system/data/cdi-hooks-02.json new file mode 100644 index 000000000..f1c560e42 --- /dev/null +++ b/test/system/data/cdi-hooks-02.json @@ -0,0 +1,19 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache", + "--folder", + "/usr/lib", + "--folder", + "/usr/lib64" + ], + "hookName": "createContainer", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-10.json b/test/system/data/cdi-hooks-10.json new file mode 100644 index 000000000..d1fb9f98d --- /dev/null +++ b/test/system/data/cdi-hooks-10.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache" + ], + "hookName": "createContainer", + "path": "" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-11.json b/test/system/data/cdi-hooks-11.json new file mode 100644 index 000000000..4995055b2 --- /dev/null +++ b/test/system/data/cdi-hooks-11.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "unknown", + "hook", + "update-ldcache" + ], + "hookName": "createContainer", + "path": "/usr/bin/unknown" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-12.json b/test/system/data/cdi-hooks-12.json new file mode 100644 index 000000000..043f651f4 --- /dev/null +++ b/test/system/data/cdi-hooks-12.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "unknown", + "update-ldcache" + ], + "hookName": "createContainer", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-13.json b/test/system/data/cdi-hooks-13.json new file mode 100644 index 000000000..8a79f1162 --- /dev/null +++ b/test/system/data/cdi-hooks-13.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "unknown" + ], + "hookName": "createContainer", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-14.json b/test/system/data/cdi-hooks-14.json new file mode 100644 index 000000000..1c232269e --- /dev/null +++ b/test/system/data/cdi-hooks-14.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache" + ], + "hookName": "invalid", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-hooks-15.json b/test/system/data/cdi-hooks-15.json new file mode 100644 index 000000000..9a641946e --- /dev/null +++ b/test/system/data/cdi-hooks-15.json @@ -0,0 +1,15 @@ +{ + "containerEdits": { + "hooks": [ + { + "args": [ + "nvidia-ctk", + "hook", + "update-ldcache" + ], + "hookName": "createRuntime", + "path": "/usr/bin/nvidia-ctk" + } + ] + } +} diff --git a/test/system/data/cdi-mounts-10.json b/test/system/data/cdi-mounts-10.json new file mode 100644 index 000000000..886a4ede4 --- /dev/null +++ b/test/system/data/cdi-mounts-10.json @@ -0,0 +1,10 @@ +{ + "containerEdits": { + "mounts": [ + { + "containerPath": "", + "hostPath": "/tmp" + } + ] + } +} diff --git a/test/system/data/cdi-mounts-11.json b/test/system/data/cdi-mounts-11.json new file mode 100644 index 000000000..20050b17d --- /dev/null +++ b/test/system/data/cdi-mounts-11.json @@ -0,0 +1,10 @@ +{ + "containerEdits": { + "mounts": [ + { + "containerPath": "/tmp", + "hostPath": "" + } + ] + } +} diff --git a/test/system/data/cdi-mounts-12.json b/test/system/data/cdi-mounts-12.json new file mode 100644 index 000000000..56ac20ce4 --- /dev/null +++ b/test/system/data/cdi-mounts-12.json @@ -0,0 +1,10 @@ +{ + "containerEdits": { + "mounts": [ + { + "containerPath": "/non/existent/path", + "hostPath": "/non/existent/path" + } + ] + } +} diff --git a/test/system/meson.build b/test/system/meson.build index 1f32ad5bf..67edea854 100644 --- a/test/system/meson.build +++ b/test/system/meson.build @@ -15,6 +15,7 @@ test_system = files( '210-ulimit.bats', '211-dbus.bats', '220-environment-variables.bats', + '230-cdi.bats', 'setup_suite.bash', 'libs/helpers.bash', )