package daemon import ( "errors" "fmt" "os/exec" "strings" "github.com/moby/moby/v2/daemon/internal/capabilities" "github.com/opencontainers/runtime-spec/specs-go" "tags.cncf.io/container-device-interface/pkg/cdi" ) const ( amdContainerRuntimeExecutableName = "amd-container-runtime" ) func setAMDGPUs(s *specs.Spec, dev *deviceInstance) error { req := dev.req if req.Count != 0 && len(req.DeviceIDs) > 0 { return errConflictCountDeviceIDs } switch { case len(req.DeviceIDs) > 0: s.Process.Env = append(s.Process.Env, "AMD_VISIBLE_DEVICES="+strings.Join(req.DeviceIDs, ",")) case req.Count > 0: s.Process.Env = append(s.Process.Env, "AMD_VISIBLE_DEVICES="+strings.Join(countToDevices(req.Count), ",")) case req.Count < 0: s.Process.Env = append(s.Process.Env, "AMD_VISIBLE_DEVICES=all") case req.Count == 0: s.Process.Env = append(s.Process.Env, "AMD_VISIBLE_DEVICES=void") } return nil } func createAMDCDIUpdater(cdiCache *cdi.Cache) func(*specs.Spec, *deviceInstance) error { return func(s *specs.Spec, dev *deviceInstance) error { vendor, err := getFirstAvailableVendor(cdiCache.ListVendors()) if err != nil { return fmt.Errorf("failed to discover GPU vendor from CDI: %w", err) } if vendor != "amd.com" { return errors.New("AMD CDI spec not found") } injector := &cdiDeviceInjector{ defaultCDIDeviceKind: "amd.com/gpu", } return injector.injectDevices(s, dev) } } func getAMDDeviceDrivers(cdiCache *cdi.Cache) *deviceDriver { var composite firstSuccessfulUpdater if cdiCache != nil { composite = append(composite, createAMDCDIUpdater(cdiCache)) } if _, err := exec.LookPath(amdContainerRuntimeExecutableName); err == nil { composite = append(composite, setAMDGPUs) } if len(composite) == 0 { return nil } // We do not support specifying driver with device requests for AMD GPUs. // Hence only use the composite updater and try cdi and runtime driver in sequence // based on availability. capset := capabilities.Set{"gpu": struct{}{}, "amd": struct{}{}} return &deviceDriver{ capset: capset, updateSpec: composite.updateSpec, } }