@@ -25,6 +25,8 @@ import (
2525 "github.com/opencontainers/runtime-spec/specs-go"
2626 "golang.org/x/mod/semver"
2727 "tags.cncf.io/container-device-interface/pkg/parser"
28+
29+ "github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
2830)
2931
3032const (
@@ -38,30 +40,33 @@ const (
3840// a map of environment variable to values that can be used to perform lookups
3941// such as requirements.
4042type CUDA struct {
41- additionalVisibleDevicesEnvVars []string
42-
43- env map [string ]string
43+ logger logger.Interface
4444
45+ env map [string ]string
4546 mounts []specs.Mount
4647
47- acceptDeviceListAsVolumeMounts bool
48- acceptEnvvarUnprivileged bool
49- isPrivileged bool
48+ isPrivileged bool
49+
50+ additionalVisibleDevicesEnvVars []string
51+ acceptDeviceListAsVolumeMounts bool
52+ acceptEnvvarUnprivileged bool
5053}
5154
5255// NewCUDAImageFromSpec creates a CUDA image from the input OCI runtime spec.
5356// The process environment is read (if present) to construc the CUDA Image.
54- func NewCUDAImageFromSpec (spec * specs.Spec ) (CUDA , error ) {
57+ func NewCUDAImageFromSpec (spec * specs.Spec , opts ... Option ) (CUDA , error ) {
5558 var env []string
5659 if spec != nil && spec .Process != nil {
5760 env = spec .Process .Env
5861 }
5962
60- return New (
63+ specOpts := [] Option {
6164 WithEnv (env ),
6265 WithMounts (spec .Mounts ),
6366 WithPrivileged (IsPrivileged ((* OCISpec )(spec ))),
64- )
67+ }
68+
69+ return New (append (opts , specOpts ... )... )
6570}
6671
6772// newCUDAImageFromEnv creates a CUDA image from the input environment. The environment
@@ -163,7 +168,7 @@ func (i CUDA) DevicesFromEnvvars(envVars ...string) VisibleDevices {
163168
164169// GetDriverCapabilities returns the requested driver capabilities.
165170func (i CUDA ) GetDriverCapabilities () DriverCapabilities {
166- env := i .Getenv ( EnvVarNvidiaDriverCapabilities )
171+ env := i .env [ EnvVarNvidiaDriverCapabilities ]
167172
168173 capabilities := make (DriverCapabilities )
169174 for _ , c := range strings .Split (env , "," ) {
@@ -174,7 +179,7 @@ func (i CUDA) GetDriverCapabilities() DriverCapabilities {
174179}
175180
176181func (i CUDA ) legacyVersion () (string , error ) {
177- cudaVersion := i .Getenv ( EnvVarCudaVersion )
182+ cudaVersion := i .env [ EnvVarCudaVersion ]
178183 majorMinor , err := parseMajorMinorVersion (cudaVersion )
179184 if err != nil {
180185 return "" , fmt .Errorf ("invalid CUDA version %v: %v" , cudaVersion , err )
@@ -224,9 +229,42 @@ func (i CUDA) OnlyFullyQualifiedCDIDevices() bool {
224229 return hasCDIdevice
225230}
226231
227- // VisibleDevicesFromEnvVar returns the set of visible devices requested through
228- // the NVIDIA_VISIBLE_DEVICES environment variable or any variables specified
229- // in visibleDevicesEnvVars.
232+ // VisibleDevices returns a list of devices requested in the container image.
233+ // If volume mount requests are enabled these are returned if requested,
234+ // otherwise device requests through environment variables are considered.
235+ // In cases where environment variable requests required privileged containers,
236+ // such devices requests are ignored.
237+ func (i CUDA ) VisibleDevices () []string {
238+ // If enabled, try and get the device list from volume mounts first
239+ if i .acceptDeviceListAsVolumeMounts {
240+ volumeMountDeviceRequests := i .visibleDevicesFromMounts ()
241+ if len (volumeMountDeviceRequests ) > 0 {
242+ return volumeMountDeviceRequests
243+ }
244+ }
245+
246+ // Get the Fallback to reading from the environment variable if privileges are correct
247+ envVarDeviceRequests := i .VisibleDevicesFromEnvVar ()
248+ if len (envVarDeviceRequests ) == 0 {
249+ return nil
250+ }
251+
252+ // If the container is privileged, or environment variable requests are
253+ // allowed for unprivileged containers, these devices are returned.
254+ if i .isPrivileged || i .acceptEnvvarUnprivileged {
255+ return envVarDeviceRequests
256+ }
257+
258+ // We log a warning if we are ignoring the environment variable requests.
259+ i .logger .Warningf ("Ignoring devices specified in NVIDIA_VISIBLE_DEVICES in unprivileged container" )
260+
261+ return nil
262+ }
263+
264+ // VisibleDevicesFromEnvVar returns the set of visible devices requested through environment variables.
265+ // If any of the preferredVisibleDeviceEnvVars are present in the image, they
266+ // are used to determine the visible devices. If this is not the caes, the
267+ // NVIDIA_VISIBLE_DEVICES environment variable is used.
230268func (i CUDA ) VisibleDevicesFromEnvVar () []string {
231269 for _ , envVar := range i .additionalVisibleDevicesEnvVars {
232270 if i .HasEnvvar (envVar ) {
@@ -284,28 +322,6 @@ func (i CUDA) DevicesFromMounts() []string {
284322 return devices
285323}
286324
287- func (i CUDA ) VisibleDevices () []string {
288- // If enabled, try and get the device list from volume mounts first
289- if i .acceptDeviceListAsVolumeMounts {
290- devices := i .visibleDevicesFromMounts ()
291- if len (devices ) > 0 {
292- return devices
293- }
294- }
295-
296- // Fallback to reading from the environment variable if privileges are correct
297- devices := i .VisibleDevicesFromEnvVar ()
298- if len (devices ) == 0 {
299- return nil
300- }
301-
302- if i .isPrivileged || i .acceptEnvvarUnprivileged {
303- return devices
304- }
305-
306- return nil
307- }
308-
309325// CDIDevicesFromMounts returns a list of CDI devices specified as mounts on the image.
310326func (i CUDA ) CDIDevicesFromMounts () []string {
311327 var devices []string
0 commit comments