diff --git a/cmd/nvidia-container-runtime-hook/container_config.go b/cmd/nvidia-container-runtime-hook/container_config.go index cfb84745..16be7179 100644 --- a/cmd/nvidia-container-runtime-hook/container_config.go +++ b/cmd/nvidia-container-runtime-hook/container_config.go @@ -242,7 +242,14 @@ func (hookConfig *hookConfig) getNvidiaConfig(image image.CUDA, privileged bool) } } -func (hookConfig *hookConfig) getContainerConfig() (config containerConfig) { +func (hookConfig *hookConfig) getContainerConfig() (config *containerConfig) { + hookConfig.Lock() + defer hookConfig.Unlock() + + if hookConfig.containerConfig != nil { + return hookConfig.containerConfig + } + var h HookState d := json.NewDecoder(os.Stdin) if err := d.Decode(&h); err != nil { @@ -271,10 +278,13 @@ func (hookConfig *hookConfig) getContainerConfig() (config containerConfig) { log.Panicln(err) } - return containerConfig{ + cc := containerConfig{ Pid: h.Pid, Rootfs: s.Root.Path, Image: i, Nvidia: hookConfig.getNvidiaConfig(i, privileged), } + hookConfig.containerConfig = &cc + + return hookConfig.containerConfig } diff --git a/cmd/nvidia-container-runtime-hook/container_config_test.go b/cmd/nvidia-container-runtime-hook/container_config_test.go index 5247e80f..8803ff86 100644 --- a/cmd/nvidia-container-runtime-hook/container_config_test.go +++ b/cmd/nvidia-container-runtime-hook/container_config_test.go @@ -487,7 +487,7 @@ func TestGetNvidiaConfig(t *testing.T) { hookCfg := tc.hookConfig if hookCfg == nil { defaultConfig, _ := config.GetDefault() - hookCfg = &hookConfig{defaultConfig} + hookCfg = &hookConfig{Config: defaultConfig} } cfg = hookCfg.getNvidiaConfig(image, tc.privileged) } diff --git a/cmd/nvidia-container-runtime-hook/hook_config.go b/cmd/nvidia-container-runtime-hook/hook_config.go index ec4e0434..ffb08b88 100644 --- a/cmd/nvidia-container-runtime-hook/hook_config.go +++ b/cmd/nvidia-container-runtime-hook/hook_config.go @@ -7,9 +7,11 @@ import ( "path" "reflect" "strings" + "sync" "github.com/NVIDIA/nvidia-container-toolkit/internal/config" "github.com/NVIDIA/nvidia-container-toolkit/internal/config/image" + "github.com/NVIDIA/nvidia-container-toolkit/internal/info" ) const ( @@ -20,7 +22,9 @@ const ( // hookConfig wraps the toolkit config. // This allows for functions to be defined on the local type. type hookConfig struct { + sync.Mutex *config.Config + containerConfig *containerConfig } // loadConfig loads the required paths for the hook config. @@ -55,7 +59,7 @@ func getHookConfig() (*hookConfig, error) { if err != nil { return nil, fmt.Errorf("failed to load config: %v", err) } - config := &hookConfig{cfg} + config := &hookConfig{Config: cfg} allSupportedDriverCapabilities := image.SupportedDriverCapabilities if config.SupportedDriverCapabilities == "all" { @@ -73,8 +77,8 @@ func getHookConfig() (*hookConfig, error) { // getConfigOption returns the toml config option associated with the // specified struct field. -func (c hookConfig) getConfigOption(fieldName string) string { - t := reflect.TypeOf(c) +func (c *hookConfig) getConfigOption(fieldName string) string { + t := reflect.TypeOf(&c) f, ok := t.FieldByName(fieldName) if !ok { return fieldName @@ -127,3 +131,21 @@ func (c *hookConfig) nvidiaContainerCliCUDACompatModeFlags() []string { } return []string{flag} } + +func (c *hookConfig) assertModeIsLegacy() error { + if c.NVIDIAContainerRuntimeHookConfig.SkipModeDetection { + return nil + } + + mr := info.NewRuntimeModeResolver( + info.WithLogger(&logInterceptor{}), + info.WithImage(&c.containerConfig.Image), + info.WithDefaultMode(info.RuntimeModeLegacy), + ) + + mode := mr.ResolveRuntimeMode(c.NVIDIAContainerRuntimeConfig.Mode) + if mode == "legacy" { + return nil + } + return fmt.Errorf("invoking the NVIDIA Container Runtime Hook directly (e.g. specifying the docker --gpus flag) is not supported. Please use the NVIDIA Container Runtime (e.g. specify the --runtime=nvidia flag) instead") +} diff --git a/cmd/nvidia-container-runtime-hook/hook_config_test.go b/cmd/nvidia-container-runtime-hook/hook_config_test.go index 19147ecf..149f7004 100644 --- a/cmd/nvidia-container-runtime-hook/hook_config_test.go +++ b/cmd/nvidia-container-runtime-hook/hook_config_test.go @@ -90,10 +90,10 @@ func TestGetHookConfig(t *testing.T) { } } - var cfg hookConfig + var cfg *hookConfig getHookConfig := func() { c, _ := getHookConfig() - cfg = *c + cfg = c } if tc.expectedPanic { diff --git a/cmd/nvidia-container-runtime-hook/main.go b/cmd/nvidia-container-runtime-hook/main.go index c77fa390..7cdb0ad8 100644 --- a/cmd/nvidia-container-runtime-hook/main.go +++ b/cmd/nvidia-container-runtime-hook/main.go @@ -55,7 +55,7 @@ func getCLIPath(config config.ContainerCLIConfig) string { } // getRootfsPath returns an absolute path. We don't need to resolve symlinks for now. -func getRootfsPath(config containerConfig) string { +func getRootfsPath(config *containerConfig) string { rootfs, err := filepath.Abs(config.Rootfs) if err != nil { log.Panicln(err) @@ -82,8 +82,8 @@ func doPrestart() { return } - if !hook.NVIDIAContainerRuntimeHookConfig.SkipModeDetection && info.ResolveAutoMode(&logInterceptor{}, hook.NVIDIAContainerRuntimeConfig.Mode, container.Image) != "legacy" { - log.Panicln("invoking the NVIDIA Container Runtime Hook directly (e.g. specifying the docker --gpus flag) is not supported. Please use the NVIDIA Container Runtime (e.g. specify the --runtime=nvidia flag) instead.") + if err := hook.assertModeIsLegacy(); err != nil { + log.Panicf("%v", err) } rootfs := getRootfsPath(container) diff --git a/cmd/nvidia-container-runtime/main_test.go b/cmd/nvidia-container-runtime/main_test.go index 749f1f0c..ab5ddee7 100644 --- a/cmd/nvidia-container-runtime/main_test.go +++ b/cmd/nvidia-container-runtime/main_test.go @@ -122,11 +122,10 @@ func TestGoodInput(t *testing.T) { err = cmdCreate.Run() require.NoError(t, err, "runtime should not return an error") - // Check config.json for NVIDIA prestart hook + // Check config.json to ensure that the NVIDIA prestart was not inserted. spec, err = cfg.getRuntimeSpec() require.NoError(t, err, "should be no errors when reading and parsing spec from config.json") - require.NotEmpty(t, spec.Hooks, "there should be hooks in config.json") - require.Equal(t, 1, nvidiaHookCount(spec.Hooks), "exactly one nvidia prestart hook should be inserted correctly into config.json") + require.Empty(t, spec.Hooks, "there should be no hooks in config.json") } // NVIDIA prestart hook already present in config file @@ -168,11 +167,10 @@ func TestDuplicateHook(t *testing.T) { output, err := cmdCreate.CombinedOutput() require.NoErrorf(t, err, "runtime should not return an error", "output=%v", string(output)) - // Check config.json for NVIDIA prestart hook + // Check config.json to ensure that the NVIDIA prestart hook was removed. spec, err = cfg.getRuntimeSpec() require.NoError(t, err, "should be no errors when reading and parsing spec from config.json") - require.NotEmpty(t, spec.Hooks, "there should be hooks in config.json") - require.Equal(t, 1, nvidiaHookCount(spec.Hooks), "exactly one nvidia prestart hook should be inserted correctly into config.json") + require.Empty(t, spec.Hooks, "there should be no hooks in config.json") } // addNVIDIAHook is a basic wrapper for an addHookModifier that is used for @@ -240,18 +238,3 @@ func (c testConfig) generateNewRuntimeSpec() error { } return nil } - -// Return number of valid NVIDIA prestart hooks in runtime spec -func nvidiaHookCount(hooks *specs.Hooks) int { - if hooks == nil { - return 0 - } - - count := 0 - for _, hook := range hooks.Prestart { - if strings.Contains(hook.Path, nvidiaHook) { - count++ - } - } - return count -} diff --git a/internal/config/image/cuda_image.go b/internal/config/image/cuda_image.go index c295d105..05d669f7 100644 --- a/internal/config/image/cuda_image.go +++ b/internal/config/image/cuda_image.go @@ -19,6 +19,7 @@ package image import ( "fmt" "path/filepath" + "slices" "strconv" "strings" @@ -281,17 +282,24 @@ func (i CUDA) cdiDeviceRequestsFromAnnotations() []string { return nil } - var devices []string - for key, value := range i.annotations { + var annotationKeys []string + for key := range i.annotations { for _, prefix := range i.annotationsPrefixes { if strings.HasPrefix(key, prefix) { - devices = append(devices, strings.Split(value, ",")...) + annotationKeys = append(annotationKeys, key) // There is no need to check additional prefixes since we // typically deduplicate devices in any case. break } } } + // We sort the annotationKeys for consistent results. + slices.Sort(annotationKeys) + + var devices []string + for _, key := range annotationKeys { + devices = append(devices, strings.Split(i.annotations[key], ",")...) + } return devices } diff --git a/internal/info/auto.go b/internal/info/auto.go index c6800da1..c321b9a7 100644 --- a/internal/info/auto.go +++ b/internal/info/auto.go @@ -23,34 +23,101 @@ import ( "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" ) -// ResolveAutoMode determines the correct mode for the platform if set to "auto" -func ResolveAutoMode(logger logger.Interface, mode string, image image.CUDA) (rmode string) { - return resolveMode(logger, mode, image, nil) +// A RuntimeMode is used to select a specific mode of operation for the NVIDIA Container Runtime. +type RuntimeMode string + +const ( + RuntimeModeLegacy = RuntimeMode("legacy") + RuntimeModeCSV = RuntimeMode("csv") + RuntimeModeCDI = RuntimeMode("cdi") + RuntimeModeJitCDI = RuntimeMode("jit-cdi") +) + +type RuntimeModeResolver interface { + ResolveRuntimeMode(string) RuntimeMode } -func resolveMode(logger logger.Interface, mode string, image image.CUDA, propertyExtractor info.PropertyExtractor) (rmode string) { +type modeResolver struct { + logger logger.Interface + // TODO: This only needs to consider the requested devices. + image *image.CUDA + propertyExtractor info.PropertyExtractor + defaultMode RuntimeMode +} + +type Option func(*modeResolver) + +func WithDefaultMode(defaultMode RuntimeMode) Option { + return func(mr *modeResolver) { + mr.defaultMode = defaultMode + } +} + +func WithLogger(logger logger.Interface) Option { + return func(mr *modeResolver) { + mr.logger = logger + } +} + +func WithImage(image *image.CUDA) Option { + return func(mr *modeResolver) { + mr.image = image + } +} + +func WithPropertyExtractor(propertyExtractor info.PropertyExtractor) Option { + return func(mr *modeResolver) { + mr.propertyExtractor = propertyExtractor + } +} + +func NewRuntimeModeResolver(opts ...Option) RuntimeModeResolver { + r := &modeResolver{ + defaultMode: RuntimeModeJitCDI, + } + for _, opt := range opts { + opt(r) + } + if r.logger == nil { + r.logger = &logger.NullLogger{} + } + + return r +} + +// ResolveAutoMode determines the correct mode for the platform if set to "auto" +func ResolveAutoMode(logger logger.Interface, mode string, image image.CUDA) (rmode RuntimeMode) { + r := modeResolver{ + logger: logger, + image: &image, + propertyExtractor: nil, + } + return r.ResolveRuntimeMode(mode) +} + +func (m *modeResolver) ResolveRuntimeMode(mode string) (rmode RuntimeMode) { if mode != "auto" { - logger.Infof("Using requested mode '%s'", mode) - return mode + m.logger.Infof("Using requested mode '%s'", mode) + return RuntimeMode(mode) } defer func() { - logger.Infof("Auto-detected mode as '%v'", rmode) + m.logger.Infof("Auto-detected mode as '%v'", rmode) }() - if image.OnlyFullyQualifiedCDIDevices() { - return "cdi" + if m.image.OnlyFullyQualifiedCDIDevices() { + return RuntimeModeCDI } nvinfo := info.New( - info.WithLogger(logger), - info.WithPropertyExtractor(propertyExtractor), + info.WithLogger(m.logger), + info.WithPropertyExtractor(m.propertyExtractor), ) switch nvinfo.ResolvePlatform() { case info.PlatformNVML, info.PlatformWSL: - return "legacy" + return m.defaultMode case info.PlatformTegra: - return "csv" + return RuntimeModeCSV } - return "legacy" + return m.defaultMode } diff --git a/internal/info/auto_test.go b/internal/info/auto_test.go index c2ab93d7..f6d99c7e 100644 --- a/internal/info/auto_test.go +++ b/internal/info/auto_test.go @@ -43,11 +43,16 @@ func TestResolveAutoMode(t *testing.T) { mode: "not-auto", expectedMode: "not-auto", }, + { + description: "legacy resolves to legacy", + mode: "legacy", + expectedMode: "legacy", + }, { description: "no info defaults to legacy", mode: "auto", info: map[string]bool{}, - expectedMode: "legacy", + expectedMode: "jit-cdi", }, { description: "non-nvml, non-tegra, nvgpu resolves to csv", @@ -80,14 +85,14 @@ func TestResolveAutoMode(t *testing.T) { expectedMode: "csv", }, { - description: "nvml, non-tegra, non-nvgpu resolves to legacy", + description: "nvml, non-tegra, non-nvgpu resolves to jit-cdi", mode: "auto", info: map[string]bool{ "nvml": true, "tegra": false, "nvgpu": false, }, - expectedMode: "legacy", + expectedMode: "jit-cdi", }, { description: "nvml, non-tegra, nvgpu resolves to csv", @@ -100,14 +105,14 @@ func TestResolveAutoMode(t *testing.T) { expectedMode: "csv", }, { - description: "nvml, tegra, non-nvgpu resolves to legacy", + description: "nvml, tegra, non-nvgpu resolves to jit-cdi", mode: "auto", info: map[string]bool{ "nvml": true, "tegra": true, "nvgpu": false, }, - expectedMode: "legacy", + expectedMode: "jit-cdi", }, { description: "nvml, tegra, nvgpu resolves to csv", @@ -136,7 +141,7 @@ func TestResolveAutoMode(t *testing.T) { }, }, { - description: "at least one non-cdi device resolves to legacy", + description: "at least one non-cdi device resolves to jit-cdi", mode: "auto", envmap: map[string]string{ "NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=0,0", @@ -146,7 +151,7 @@ func TestResolveAutoMode(t *testing.T) { "tegra": false, "nvgpu": false, }, - expectedMode: "legacy", + expectedMode: "jit-cdi", }, { description: "at least one non-cdi device resolves to csv", @@ -170,7 +175,7 @@ func TestResolveAutoMode(t *testing.T) { expectedMode: "cdi", }, { - description: "cdi mount and non-CDI devices resolves to legacy", + description: "cdi mount and non-CDI devices resolves to jit-cdi", mode: "auto", mounts: []string{ "/var/run/nvidia-container-devices/cdi/nvidia.com/gpu/0", @@ -181,7 +186,7 @@ func TestResolveAutoMode(t *testing.T) { "tegra": false, "nvgpu": false, }, - expectedMode: "legacy", + expectedMode: "jit-cdi", }, { description: "cdi mount and non-CDI envvar resolves to cdi", @@ -199,22 +204,6 @@ func TestResolveAutoMode(t *testing.T) { }, expectedMode: "cdi", }, - { - description: "non-cdi mount and CDI envvar resolves to legacy", - mode: "auto", - envmap: map[string]string{ - "NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=0", - }, - mounts: []string{ - "/var/run/nvidia-container-devices/0", - }, - info: map[string]bool{ - "nvml": true, - "tegra": false, - "nvgpu": false, - }, - expectedMode: "legacy", - }, } for _, tc := range testCases { @@ -251,7 +240,12 @@ func TestResolveAutoMode(t *testing.T) { image.WithAcceptDeviceListAsVolumeMounts(true), image.WithAcceptEnvvarUnprivileged(true), ) - mode := resolveMode(logger, tc.mode, image, properties) + mr := NewRuntimeModeResolver( + WithLogger(logger), + WithImage(&image), + WithPropertyExtractor(properties), + ) + mode := mr.ResolveRuntimeMode(tc.mode) require.EqualValues(t, tc.expectedMode, mode) }) } diff --git a/internal/modifier/cdi.go b/internal/modifier/cdi.go index ff75eccc..b5d98435 100644 --- a/internal/modifier/cdi.go +++ b/internal/modifier/cdi.go @@ -18,6 +18,7 @@ package modifier import ( "fmt" + "strings" "tags.cncf.io/container-device-interface/pkg/parser" @@ -27,17 +28,27 @@ import ( "github.com/NVIDIA/nvidia-container-toolkit/internal/modifier/cdi" "github.com/NVIDIA/nvidia-container-toolkit/internal/oci" "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi" - "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec" +) + +const ( + automaticDeviceVendor = "runtime.nvidia.com" + automaticDeviceClass = "gpu" + automaticDeviceKind = automaticDeviceVendor + "/" + automaticDeviceClass + automaticDevicePrefix = automaticDeviceKind + "=" ) // NewCDIModifier creates an OCI spec modifier that determines the modifications to make based on the // CDI specifications available on the system. The NVIDIA_VISIBLE_DEVICES environment variable is // used to select the devices to include. -func NewCDIModifier(logger logger.Interface, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) { +func NewCDIModifier(logger logger.Interface, cfg *config.Config, image image.CUDA, isJitCDI bool) (oci.SpecModifier, error) { + defaultKind := cfg.NVIDIAContainerRuntimeConfig.Modes.CDI.DefaultKind + if isJitCDI { + defaultKind = automaticDeviceKind + } deviceRequestor := newCDIDeviceRequestor( logger, image, - cfg.NVIDIAContainerRuntimeConfig.Modes.CDI.DefaultKind, + defaultKind, ) devices := deviceRequestor.DeviceRequests() if len(devices) == 0 { @@ -107,17 +118,36 @@ func (c *cdiDeviceRequestor) DeviceRequests() []string { func filterAutomaticDevices(devices []string) []string { var automatic []string for _, device := range devices { - vendor, class, _ := parser.ParseDevice(device) - if vendor == "runtime.nvidia.com" && class == "gpu" { - automatic = append(automatic, device) + if !strings.HasPrefix(device, automaticDevicePrefix) { + continue } + automatic = append(automatic, device) } return automatic } func newAutomaticCDISpecModifier(logger logger.Interface, cfg *config.Config, devices []string) (oci.SpecModifier, error) { logger.Debugf("Generating in-memory CDI specs for devices %v", devices) - spec, err := generateAutomaticCDISpec(logger, cfg, devices) + + var identifiers []string + for _, device := range devices { + identifiers = append(identifiers, strings.TrimPrefix(device, automaticDevicePrefix)) + } + + cdilib, err := nvcdi.New( + nvcdi.WithLogger(logger), + nvcdi.WithNVIDIACDIHookPath(cfg.NVIDIACTKConfig.Path), + nvcdi.WithDriverRoot(cfg.NVIDIAContainerCLIConfig.Root), + nvcdi.WithVendor(automaticDeviceVendor), + nvcdi.WithClass(automaticDeviceClass), + ) + if err != nil { + return nil, fmt.Errorf("failed to construct CDI library: %w", err) + } + + // TODO: We should try to load the kernel modules and create the device nodes here. + // Failures should raise a warning and not error out. + spec, err := cdilib.GetSpec(identifiers...) if err != nil { return nil, fmt.Errorf("failed to generate CDI spec: %w", err) } @@ -132,27 +162,6 @@ func newAutomaticCDISpecModifier(logger logger.Interface, cfg *config.Config, de return cdiDeviceRequestor, nil } -func generateAutomaticCDISpec(logger logger.Interface, cfg *config.Config, devices []string) (spec.Interface, error) { - cdilib, err := nvcdi.New( - nvcdi.WithLogger(logger), - nvcdi.WithNVIDIACDIHookPath(cfg.NVIDIACTKConfig.Path), - nvcdi.WithDriverRoot(cfg.NVIDIAContainerCLIConfig.Root), - nvcdi.WithVendor("runtime.nvidia.com"), - nvcdi.WithClass("gpu"), - ) - if err != nil { - return nil, fmt.Errorf("failed to construct CDI library: %w", err) - } - - var identifiers []string - for _, device := range devices { - _, _, id := parser.ParseDevice(device) - identifiers = append(identifiers, id) - } - - return cdilib.GetSpec(identifiers...) -} - type deduplicatedDeviceRequestor struct { deviceRequestor } diff --git a/internal/modifier/cdi_test.go b/internal/modifier/cdi_test.go index 881e8b2c..0163e4ce 100644 --- a/internal/modifier/cdi_test.go +++ b/internal/modifier/cdi_test.go @@ -70,6 +70,18 @@ func TestDeviceRequests(t *testing.T) { }, expectedDevices: []string{"nvidia.com/gpu=0", "example.com/class=device"}, }, + { + description: "cdi devices from envvar with default kind", + input: cdiDeviceRequestor{ + defaultKind: "runtime.nvidia.com/gpu", + }, + spec: &specs.Spec{ + Process: &specs.Process{ + Env: []string{"NVIDIA_VISIBLE_DEVICES=all"}, + }, + }, + expectedDevices: []string{"runtime.nvidia.com/gpu=all"}, + }, { description: "no matching annotations", prefixes: []string{"not-prefix/"}, @@ -98,7 +110,7 @@ func TestDeviceRequests(t *testing.T) { "another-prefix/bar": "example.com/device=baz", }, }, - expectedDevices: []string{"example.com/device=bar", "example.com/device=baz"}, + expectedDevices: []string{"example.com/device=baz", "example.com/device=bar"}, }, { description: "multiple matching annotations with duplicate devices", diff --git a/internal/runtime/runtime_factory.go b/internal/runtime/runtime_factory.go index a4e992c1..b159aa9a 100644 --- a/internal/runtime/runtime_factory.go +++ b/internal/runtime/runtime_factory.go @@ -101,14 +101,14 @@ func newSpecModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Sp return modifiers, nil } -func newModeModifier(logger logger.Interface, mode string, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) { +func newModeModifier(logger logger.Interface, mode info.RuntimeMode, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) { switch mode { - case "legacy": + case info.RuntimeModeLegacy: return modifier.NewStableRuntimeModifier(logger, cfg.NVIDIAContainerRuntimeHookConfig.Path), nil - case "csv": + case info.RuntimeModeCSV: return modifier.NewCSVModifier(logger, cfg, image) - case "cdi": - return modifier.NewCDIModifier(logger, cfg, image) + case info.RuntimeModeCDI, info.RuntimeModeJitCDI: + return modifier.NewCDIModifier(logger, cfg, image, mode == info.RuntimeModeJitCDI) } return nil, fmt.Errorf("invalid runtime mode: %v", cfg.NVIDIAContainerRuntimeConfig.Mode) @@ -119,7 +119,7 @@ func newModeModifier(logger logger.Interface, mode string, cfg *config.Config, i // The image is also used to determine the runtime mode to apply. // If a non-CDI mode is detected we ensure that the image does not process // annotation devices. -func initRuntimeModeAndImage(logger logger.Interface, cfg *config.Config, ociSpec oci.Spec) (string, *image.CUDA, error) { +func initRuntimeModeAndImage(logger logger.Interface, cfg *config.Config, ociSpec oci.Spec) (info.RuntimeMode, *image.CUDA, error) { rawSpec, err := ociSpec.Load() if err != nil { return "", nil, fmt.Errorf("failed to load OCI spec: %v", err) @@ -136,9 +136,13 @@ func initRuntimeModeAndImage(logger logger.Interface, cfg *config.Config, ociSpe return "", nil, err } - mode := info.ResolveAutoMode(logger, cfg.NVIDIAContainerRuntimeConfig.Mode, image) + modeResolver := info.NewRuntimeModeResolver( + info.WithLogger(logger), + info.WithImage(&image), + ) + mode := modeResolver.ResolveRuntimeMode(cfg.NVIDIAContainerRuntimeConfig.Mode) // We update the mode here so that we can continue passing just the config to other functions. - cfg.NVIDIAContainerRuntimeConfig.Mode = mode + cfg.NVIDIAContainerRuntimeConfig.Mode = string(mode) if mode == "cdi" || len(cfg.NVIDIAContainerRuntimeConfig.Modes.CDI.AnnotationPrefixes) == 0 { return mode, &image, nil @@ -154,12 +158,12 @@ func initRuntimeModeAndImage(logger logger.Interface, cfg *config.Config, ociSpe } // supportedModifierTypes returns the modifiers supported for a specific runtime mode. -func supportedModifierTypes(mode string) []string { +func supportedModifierTypes(mode info.RuntimeMode) []string { switch mode { - case "cdi": + case info.RuntimeModeCDI, info.RuntimeModeJitCDI: // For CDI mode we make no additional modifications. return []string{"nvidia-hook-remover", "mode"} - case "csv": + case info.RuntimeModeCSV: // For CSV mode we support mode and feature-gated modification. return []string{"nvidia-hook-remover", "feature-gated", "mode"} default: diff --git a/tests/output/bundle/config.json b/tests/output/bundle/config.json new file mode 100644 index 00000000..f8dd9a6a --- /dev/null +++ b/tests/output/bundle/config.json @@ -0,0 +1 @@ +{"ociVersion":"1.0.1-dev","process":{"terminal":true,"user":{"uid":0,"gid":0},"args":["sh"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","TERM=xterm"],"cwd":"/","capabilities":{"bounding":["CAP_AUDIT_WRITE","CAP_KILL","CAP_NET_BIND_SERVICE"],"effective":["CAP_AUDIT_WRITE","CAP_KILL","CAP_NET_BIND_SERVICE"],"inheritable":["CAP_AUDIT_WRITE","CAP_KILL","CAP_NET_BIND_SERVICE"],"permitted":["CAP_AUDIT_WRITE","CAP_KILL","CAP_NET_BIND_SERVICE"],"ambient":["CAP_AUDIT_WRITE","CAP_KILL","CAP_NET_BIND_SERVICE"]},"rlimits":[{"type":"RLIMIT_NOFILE","hard":1024,"soft":1024}],"noNewPrivileges":true},"root":{"path":"rootfs","readonly":true},"hostname":"runc","mounts":[{"destination":"/proc","type":"proc","source":"proc"},{"destination":"/dev","type":"tmpfs","source":"tmpfs","options":["nosuid","strictatime","mode=755","size=65536k"]},{"destination":"/dev/pts","type":"devpts","source":"devpts","options":["nosuid","noexec","newinstance","ptmxmode=0666","mode=0620","gid=5"]},{"destination":"/dev/shm","type":"tmpfs","source":"shm","options":["nosuid","noexec","nodev","mode=1777","size=65536k"]},{"destination":"/dev/mqueue","type":"mqueue","source":"mqueue","options":["nosuid","noexec","nodev"]},{"destination":"/sys","type":"sysfs","source":"sysfs","options":["nosuid","noexec","nodev","ro"]},{"destination":"/sys/fs/cgroup","type":"cgroup","source":"cgroup","options":["nosuid","noexec","nodev","relatime","ro"]}],"hooks":{},"linux":{"resources":{"devices":[{"allow":false,"access":"rwm"}]},"namespaces":[{"type":"pid"},{"type":"network"},{"type":"ipc"},{"type":"uts"},{"type":"mount"}],"maskedPaths":["/proc/kcore","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/sys/firmware","/proc/scsi"],"readonlyPaths":["/proc/asound","/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]}}