Use toml representation to get defaults

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar 2023-03-13 15:22:18 +02:00
parent 90c4c4811a
commit 1bd5798a99
9 changed files with 86 additions and 184 deletions

View File

@ -496,7 +496,7 @@ func TestGetNvidiaConfig(t *testing.T) {
getConfig := func() { getConfig := func() {
hookConfig := tc.hookConfig hookConfig := tc.hookConfig
if hookConfig == nil { if hookConfig == nil {
defaultConfig := getDefaultHookConfig() defaultConfig, _ := getDefaultHookConfig()
hookConfig = &defaultConfig hookConfig = &defaultConfig
} }
config = getNvidiaConfig(hookConfig, tc.env, nil, tc.privileged) config = getNvidiaConfig(hookConfig, tc.env, nil, tc.privileged)
@ -708,7 +708,7 @@ func TestDeviceListSourcePriority(t *testing.T) {
env := map[string]string{ env := map[string]string{
envNVVisibleDevices: tc.envvarDevices, envNVVisibleDevices: tc.envvarDevices,
} }
hookConfig := getDefaultHookConfig() hookConfig, _ := getDefaultHookConfig()
hookConfig.AcceptEnvvarUnprivileged = tc.acceptUnprivileged hookConfig.AcceptEnvvarUnprivileged = tc.acceptUnprivileged
hookConfig.AcceptDeviceListAsVolumeMounts = tc.acceptMounts hookConfig.AcceptDeviceListAsVolumeMounts = tc.acceptMounts
devices = getDevices(&hookConfig, env, tc.mountDevices, tc.privileged) devices = getDevices(&hookConfig, env, tc.mountDevices, tc.privileged)

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"log" "log"
"os" "os"
"path" "path"
@ -48,8 +49,18 @@ type HookConfig struct {
NVIDIAContainerRuntimeHook config.RuntimeHookConfig `toml:"nvidia-container-runtime-hook"` NVIDIAContainerRuntimeHook config.RuntimeHookConfig `toml:"nvidia-container-runtime-hook"`
} }
func getDefaultHookConfig() HookConfig { func getDefaultHookConfig() (HookConfig, error) {
return HookConfig{ rtConfig, err := config.GetDefaultRuntimeConfig()
if err != nil {
return HookConfig{}, err
}
rtHookConfig, err := config.GetDefaultRuntimeHookConfig()
if err != nil {
return HookConfig{}, err
}
c := HookConfig{
DisableRequire: false, DisableRequire: false,
SwarmResource: nil, SwarmResource: nil,
AcceptEnvvarUnprivileged: true, AcceptEnvvarUnprivileged: true,
@ -67,28 +78,37 @@ func getDefaultHookConfig() HookConfig {
User: nil, User: nil,
Ldconfig: nil, Ldconfig: nil,
}, },
NVIDIAContainerRuntime: *config.GetDefaultRuntimeConfig(), NVIDIAContainerRuntime: *rtConfig,
NVIDIAContainerRuntimeHook: *config.GetDefaultRuntimeHookConfig(), NVIDIAContainerRuntimeHook: *rtHookConfig,
} }
return c, nil
} }
func getHookConfig() (config HookConfig) { func getHookConfig() (*HookConfig, error) {
var err error var err error
var config HookConfig
if len(*configflag) > 0 { if len(*configflag) > 0 {
config = getDefaultHookConfig() config, err = getDefaultHookConfig()
if err != nil {
return nil, fmt.Errorf("couldn't get default configuration: %v", err)
}
_, err = toml.DecodeFile(*configflag, &config) _, err = toml.DecodeFile(*configflag, &config)
if err != nil { if err != nil {
log.Panicln("couldn't open configuration file:", err) return nil, fmt.Errorf("couldn't open configuration file: %v", err)
} }
} else { } else {
for _, p := range defaultPaths { for _, p := range defaultPaths {
config = getDefaultHookConfig() config, err = getDefaultHookConfig()
if err != nil {
return nil, fmt.Errorf("couldn't get default configuration: %v", err)
}
_, err = toml.DecodeFile(p, &config) _, err = toml.DecodeFile(p, &config)
if err == nil { if err == nil {
break break
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
log.Panicln("couldn't open default configuration file:", err) return nil, fmt.Errorf("couldn't open default configuration file: %v", err)
} }
} }
} }
@ -102,7 +122,7 @@ func getHookConfig() (config HookConfig) {
log.Panicf("Invalid value for config option '%v'; %v (supported: %v)\n", configName, config.SupportedDriverCapabilities, allDriverCapabilities) log.Panicf("Invalid value for config option '%v'; %v (supported: %v)\n", configName, config.SupportedDriverCapabilities, allDriverCapabilities)
} }
return config return &config, nil
} }
// getConfigOption returns the toml config option associated with the // getConfigOption returns the toml config option associated with the

View File

@ -89,7 +89,8 @@ func TestGetHookConfig(t *testing.T) {
var config HookConfig var config HookConfig
getHookConfig := func() { getHookConfig := func() {
config = getHookConfig() c, _ := getHookConfig()
config = *c
} }
if tc.expectedPanic { if tc.expectedPanic {

View File

@ -71,14 +71,17 @@ func doPrestart() {
defer exit() defer exit()
log.SetFlags(0) log.SetFlags(0)
hook := getHookConfig() hook, err := getHookConfig()
if err != nil || hook == nil {
log.Panicln("error getting hook config:", err)
}
cli := hook.NvidiaContainerCLI cli := hook.NvidiaContainerCLI
if !hook.NVIDIAContainerRuntimeHook.SkipModeDetection && info.ResolveAutoMode(&logInterceptor{}, hook.NVIDIAContainerRuntime.Mode) != "legacy" { if !hook.NVIDIAContainerRuntimeHook.SkipModeDetection && info.ResolveAutoMode(&logInterceptor{}, hook.NVIDIAContainerRuntime.Mode) != "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.") 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.")
} }
container := getContainerConfig(hook) container := getContainerConfig(*hook)
nvidia := container.Nvidia nvidia := container.Nvidia
if nvidia == nil { if nvidia == nil {
// Not a GPU container, nothing to do. // Not a GPU container, nothing to do.

View File

@ -16,33 +16,7 @@
package config package config
import (
"github.com/pelletier/go-toml"
)
// ContainerCLIConfig stores the options for the nvidia-container-cli // ContainerCLIConfig stores the options for the nvidia-container-cli
type ContainerCLIConfig struct { type ContainerCLIConfig struct {
Root string `toml:"root"` Root string `toml:"root"`
} }
// getContainerCLIConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getContainerCLIConfigFrom(toml *toml.Tree) *ContainerCLIConfig {
cfg := getDefaultContainerCLIConfig()
if toml == nil {
return cfg
}
cfg.Root = toml.GetDefault("nvidia-container-cli.root", cfg.Root).(string)
return cfg
}
// getDefaultContainerCLIConfig defines the default values for the config
func getDefaultContainerCLIConfig() *ContainerCLIConfig {
c := ContainerCLIConfig{
Root: "",
}
return &c
}

View File

@ -66,7 +66,7 @@ func GetConfig() (*Config, error) {
tomlFile, err := os.Open(configFilePath) tomlFile, err := os.Open(configFilePath)
if err != nil { if err != nil {
return getDefaultConfig(), nil return getDefaultConfig()
} }
defer tomlFile.Close() defer tomlFile.Close()
@ -90,41 +90,53 @@ func loadConfigFrom(reader io.Reader) (*Config, error) {
// getConfigFrom reads the nvidia container runtime config from the specified toml Tree. // getConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getConfigFrom(toml *toml.Tree) (*Config, error) { func getConfigFrom(toml *toml.Tree) (*Config, error) {
cfg := getDefaultConfig() cfg, err := getDefaultConfig()
if toml == nil {
return cfg, nil
}
cfg.AcceptEnvvarUnprivileged = toml.GetDefault("accept-nvidia-visible-devices-envvar-when-unprivileged", cfg.AcceptEnvvarUnprivileged).(bool)
cfg.NVIDIAContainerCLIConfig = *getContainerCLIConfigFrom(toml)
cfg.NVIDIACTKConfig = *getCTKConfigFrom(toml)
runtimeConfig, err := getRuntimeConfigFrom(toml)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load nvidia-container-runtime config: %v", err) return nil, err
} }
cfg.NVIDIAContainerRuntimeConfig = *runtimeConfig
runtimeHookConfig, err := getRuntimeHookConfigFrom(toml) if err := toml.Unmarshal(cfg); err != nil {
if err != nil { return nil, fmt.Errorf("failed to unmarshal config: %v", err)
return nil, fmt.Errorf("failed to load nvidia-container-runtime-hook config: %v", err)
} }
cfg.NVIDIAContainerRuntimeHookConfig = *runtimeHookConfig
return cfg, nil return cfg, nil
} }
// getDefaultConfig defines the default values for the config // getDefaultConfig defines the default values for the config
func getDefaultConfig() *Config { func getDefaultConfig() (*Config, error) {
c := Config{ tomlConfig, err := GetDefaultConfigToml()
AcceptEnvvarUnprivileged: true, if err != nil {
NVIDIAContainerCLIConfig: *getDefaultContainerCLIConfig(), return nil, err
NVIDIACTKConfig: *getDefaultCTKConfig(),
NVIDIAContainerRuntimeConfig: *GetDefaultRuntimeConfig(),
} }
return &c // tomlConfig above includes information about the default values and comments.
// we need to marshal it back to a string and then unmarshal it to strip the comments.
contents, err := tomlConfig.ToTomlString()
if err != nil {
return nil, err
}
reloaded, err := toml.Load(contents)
if err != nil {
return nil, err
}
d := Config{}
if err := reloaded.Unmarshal(&d); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %v", err)
}
// The default value for the accept-nvidia-visible-devices-envvar-when-unprivileged is non-standard.
// As such we explicitly handle it being set here.
if reloaded.Get("accept-nvidia-visible-devices-envvar-when-unprivileged") == nil {
d.AcceptEnvvarUnprivileged = true
}
// The default value for the nvidia-container-runtime.debug is non-standard.
// As such we explicitly handle it being set here.
if reloaded.Get("nvidia-container-runtime.debug") == nil {
d.NVIDIAContainerRuntimeConfig.DebugFilePath = "/dev/null"
}
return &d, nil
} }
// GetDefaultConfigToml returns the default config as a toml Tree. // GetDefaultConfigToml returns the default config as a toml Tree.

View File

@ -16,47 +16,18 @@
package config package config
import (
"fmt"
"github.com/pelletier/go-toml"
)
// RuntimeHookConfig stores the config options for the NVIDIA Container Runtime // RuntimeHookConfig stores the config options for the NVIDIA Container Runtime
type RuntimeHookConfig struct { type RuntimeHookConfig struct {
// SkipModeDetection disables the mode check for the runtime hook. // SkipModeDetection disables the mode check for the runtime hook.
SkipModeDetection bool `toml:"skip-mode-detection"` SkipModeDetection bool `toml:"skip-mode-detection"`
} }
// dummyHookConfig allows us to unmarshal only a RuntimeHookConfig from a *toml.Tree
type dummyHookConfig struct {
RuntimeHook RuntimeHookConfig `toml:"nvidia-container-runtime-hook"`
}
// getRuntimeHookConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getRuntimeHookConfigFrom(toml *toml.Tree) (*RuntimeHookConfig, error) {
cfg := GetDefaultRuntimeHookConfig()
if toml == nil {
return cfg, nil
}
d := dummyHookConfig{
RuntimeHook: *cfg,
}
if err := toml.Unmarshal(&d); err != nil {
return nil, fmt.Errorf("failed to unmarshal runtime config: %v", err)
}
return &d.RuntimeHook, nil
}
// GetDefaultRuntimeHookConfig defines the default values for the config // GetDefaultRuntimeHookConfig defines the default values for the config
func GetDefaultRuntimeHookConfig() *RuntimeHookConfig { func GetDefaultRuntimeHookConfig() (*RuntimeHookConfig, error) {
c := RuntimeHookConfig{ cfg, err := getDefaultConfig()
SkipModeDetection: false, if err != nil {
return nil, err
} }
return &c return &cfg.NVIDIAContainerRuntimeHookConfig, nil
} }

View File

@ -16,21 +16,6 @@
package config package config
import (
"fmt"
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
"github.com/pelletier/go-toml"
"github.com/sirupsen/logrus"
)
const (
dockerRuncExecutableName = "docker-runc"
runcExecutableName = "runc"
auto = "auto"
)
// RuntimeConfig stores the config options for the NVIDIA Container Runtime // RuntimeConfig stores the config options for the NVIDIA Container Runtime
type RuntimeConfig struct { type RuntimeConfig struct {
DebugFilePath string `toml:"debug"` DebugFilePath string `toml:"debug"`
@ -61,52 +46,12 @@ type csvModeConfig struct {
MountSpecPath string `toml:"mount-spec-path"` MountSpecPath string `toml:"mount-spec-path"`
} }
// dummy allows us to unmarshal only a RuntimeConfig from a *toml.Tree
type dummy struct {
Runtime RuntimeConfig `toml:"nvidia-container-runtime"`
}
// getRuntimeConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getRuntimeConfigFrom(toml *toml.Tree) (*RuntimeConfig, error) {
cfg := GetDefaultRuntimeConfig()
if toml == nil {
return cfg, nil
}
d := dummy{
Runtime: *cfg,
}
if err := toml.Unmarshal(&d); err != nil {
return nil, fmt.Errorf("failed to unmarshal runtime config: %v", err)
}
return &d.Runtime, nil
}
// GetDefaultRuntimeConfig defines the default values for the config // GetDefaultRuntimeConfig defines the default values for the config
func GetDefaultRuntimeConfig() *RuntimeConfig { func GetDefaultRuntimeConfig() (*RuntimeConfig, error) {
c := RuntimeConfig{ cfg, err := getDefaultConfig()
DebugFilePath: "/dev/null", if err != nil {
LogLevel: logrus.InfoLevel.String(), return nil, err
Runtimes: []string{
dockerRuncExecutableName,
runcExecutableName,
},
Mode: auto,
Modes: modesConfig{
CSV: csvModeConfig{
MountSpecPath: "/etc/nvidia-container-runtime/host-files-for-container.d",
},
CDI: cdiModeConfig{
DefaultKind: "nvidia.com/gpu",
AnnotationPrefixes: []string{
cdi.AnnotationPrefix,
},
},
},
} }
return &c return &cfg.NVIDIAContainerRuntimeConfig, nil
} }

View File

@ -16,31 +16,7 @@
package config package config
import "github.com/pelletier/go-toml"
// CTKConfig stores the config options for the NVIDIA Container Toolkit CLI (nvidia-ctk) // CTKConfig stores the config options for the NVIDIA Container Toolkit CLI (nvidia-ctk)
type CTKConfig struct { type CTKConfig struct {
Path string `toml:"path"` Path string `toml:"path"`
} }
// getCTKConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getCTKConfigFrom(toml *toml.Tree) *CTKConfig {
cfg := getDefaultCTKConfig()
if toml == nil {
return cfg
}
cfg.Path = toml.GetDefault("nvidia-ctk.path", cfg.Path).(string)
return cfg
}
// getDefaultCTKConfig defines the default values for the config
func getDefaultCTKConfig() *CTKConfig {
c := CTKConfig{
Path: "nvidia-ctk",
}
return &c
}