Read top-level config to propagate Root to experimental runtime

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar
2022-03-29 12:01:12 +02:00
parent 33d9c1dd57
commit d12dbd1bef
9 changed files with 206 additions and 84 deletions

48
internal/config/cli.go Normal file
View File

@@ -0,0 +1,48 @@
/**
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
#
# 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 config
import (
"github.com/pelletier/go-toml"
)
// CLIConfig stores the options for the nvidia-container-cli
type CLIConfig struct {
Root string
}
// getCLIConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getCLIConfigFrom(toml *toml.Tree) *CLIConfig {
cfg := getDefaultCLIConfig()
if toml == nil {
return cfg
}
cfg.Root = toml.GetDefault("nvidia-container-cli.root", cfg.Root).(string)
return cfg
}
// getDefaultCLIConfig defines the default values for the config
func getDefaultCLIConfig() *CLIConfig {
c := CLIConfig{
Root: "",
}
return &c
}

99
internal/config/config.go Normal file
View File

@@ -0,0 +1,99 @@
/**
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
#
# 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 config
import (
"fmt"
"io"
"os"
"path"
"github.com/pelletier/go-toml"
)
const (
configOverride = "XDG_CONFIG_HOME"
configFilePath = "nvidia-container-runtime/config.toml"
)
var (
configDir = "/etc/"
)
// Config represents the contents of the config.toml file for the NVIDIA Container Toolkit
// Note: This is currently duplicated by the HookConfig in cmd/nvidia-container-toolkit/hook_config.go
type Config struct {
NVIDIAContainerCLIConfig CLIConfig `toml:"nvidia-container-cli"`
NVIDIAContainerRuntimeConfig RuntimeConfig `toml:"nvidia-container-runtime"`
}
// GetConfig sets up the config struct. Values are read from a toml file
// or set via the environment.
func GetConfig() (*Config, error) {
if XDGConfigDir := os.Getenv(configOverride); len(XDGConfigDir) != 0 {
configDir = XDGConfigDir
}
configFilePath := path.Join(configDir, configFilePath)
tomlFile, err := os.Open(configFilePath)
if err != nil {
return nil, fmt.Errorf("failed to open config file %v: %v", configFilePath, err)
}
defer tomlFile.Close()
cfg, err := loadConfigFrom(tomlFile)
if err != nil {
return nil, fmt.Errorf("failed to read config values: %v", err)
}
return cfg, nil
}
// loadRuntimeConfigFrom reads the config from the specified Reader
func loadConfigFrom(reader io.Reader) (*Config, error) {
toml, err := toml.LoadReader(reader)
if err != nil {
return nil, err
}
return getConfigFrom(toml), nil
}
// getConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getConfigFrom(toml *toml.Tree) *Config {
cfg := getDefaultConfig()
if toml == nil {
return cfg
}
cfg.NVIDIAContainerCLIConfig = *getCLIConfigFrom(toml)
cfg.NVIDIAContainerRuntimeConfig = *getRuntimeConfigFrom(toml)
return cfg
}
// getDefaultConfig defines the default values for the config
func getDefaultConfig() *Config {
c := Config{
NVIDIAContainerCLIConfig: *getDefaultCLIConfig(),
NVIDIAContainerRuntimeConfig: *getDefaultRuntimeConfig(),
}
return &c
}

View File

@@ -17,23 +17,9 @@
package config
import (
"fmt"
"io"
"os"
"path"
"github.com/pelletier/go-toml"
)
const (
configOverride = "XDG_CONFIG_HOME"
configFilePath = "nvidia-container-runtime/config.toml"
)
var (
configDir = "/etc/"
)
// RuntimeConfig stores the config options for the NVIDIA Container Runtime
type RuntimeConfig struct {
DebugFilePath string
@@ -41,39 +27,6 @@ type RuntimeConfig struct {
DiscoverMode string
}
// GetRuntimeConfig sets up the config struct. Values are read from a toml file
// or set via the environment.
func GetRuntimeConfig() (*RuntimeConfig, error) {
if XDGConfigDir := os.Getenv(configOverride); len(XDGConfigDir) != 0 {
configDir = XDGConfigDir
}
configFilePath := path.Join(configDir, configFilePath)
tomlFile, err := os.Open(configFilePath)
if err != nil {
return nil, fmt.Errorf("failed to open config file %v: %v", configFilePath, err)
}
defer tomlFile.Close()
cfg, err := loadRuntimeConfigFrom(tomlFile)
if err != nil {
return nil, fmt.Errorf("failed to read config values: %v", err)
}
return cfg, nil
}
// loadRuntimeConfigFrom reads the config from the specified Reader
func loadRuntimeConfigFrom(reader io.Reader) (*RuntimeConfig, error) {
toml, err := toml.LoadReader(reader)
if err != nil {
return nil, err
}
return getRuntimeConfigFrom(toml), nil
}
// getRuntimeConfigFrom reads the nvidia container runtime config from the specified toml Tree.
func getRuntimeConfigFrom(toml *toml.Tree) *RuntimeConfig {
cfg := getDefaultRuntimeConfig()

View File

@@ -26,7 +26,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestGerRuntimeConfigWithCustomConfig(t *testing.T) {
func TestGetConfigWithCustomConfig(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
@@ -42,24 +42,29 @@ func TestGerRuntimeConfigWithCustomConfig(t *testing.T) {
defer func() { require.NoError(t, os.RemoveAll(testDir)) }()
cfg, err := GetRuntimeConfig()
cfg, err := GetConfig()
require.NoError(t, err)
require.Equal(t, cfg.DebugFilePath, "/nvidia-container-toolkit.log")
require.Equal(t, cfg.NVIDIAContainerRuntimeConfig.DebugFilePath, "/nvidia-container-toolkit.log")
}
func TestGerRuntimeConfig(t *testing.T) {
func TestGetConfig(t *testing.T) {
testCases := []struct {
description string
contents []string
expectedError error
expectedConfig *RuntimeConfig
expectedConfig *Config
}{
{
description: "empty config is default",
expectedConfig: &RuntimeConfig{
DebugFilePath: "/dev/null",
Experimental: false,
DiscoverMode: "legacy",
expectedConfig: &Config{
NVIDIAContainerCLIConfig: CLIConfig{
Root: "",
},
NVIDIAContainerRuntimeConfig: RuntimeConfig{
DebugFilePath: "/dev/null",
Experimental: false,
DiscoverMode: "legacy",
},
},
},
{
@@ -69,10 +74,15 @@ func TestGerRuntimeConfig(t *testing.T) {
"nvidia-container-runtime.experimental = true",
"nvidia-container-runtime.discover-mode = \"not-legacy\"",
},
expectedConfig: &RuntimeConfig{
DebugFilePath: "/foo/bar",
Experimental: true,
DiscoverMode: "not-legacy",
expectedConfig: &Config{
NVIDIAContainerCLIConfig: CLIConfig{
Root: "",
},
NVIDIAContainerRuntimeConfig: RuntimeConfig{
DebugFilePath: "/foo/bar",
Experimental: true,
DiscoverMode: "not-legacy",
},
},
},
{
@@ -83,10 +93,15 @@ func TestGerRuntimeConfig(t *testing.T) {
"experimental = true",
"discover-mode = \"not-legacy\"",
},
expectedConfig: &RuntimeConfig{
DebugFilePath: "/foo/bar",
Experimental: true,
DiscoverMode: "not-legacy",
expectedConfig: &Config{
NVIDIAContainerCLIConfig: CLIConfig{
Root: "",
},
NVIDIAContainerRuntimeConfig: RuntimeConfig{
DebugFilePath: "/foo/bar",
Experimental: true,
DiscoverMode: "not-legacy",
},
},
},
}
@@ -95,7 +110,7 @@ func TestGerRuntimeConfig(t *testing.T) {
t.Run(tc.description, func(t *testing.T) {
reader := strings.NewReader(strings.Join(tc.contents, "\n"))
cfg, err := loadRuntimeConfigFrom(reader)
cfg, err := loadConfigFrom(reader)
if tc.expectedError != nil {
require.Error(t, err)
} else {