Skip to content

Commit 29fd206

Browse files
author
Evan Lezar
committed
Merge branch 'cherry-pick-1.14.4' into 'release-1.14'
Cherry pick changes for v1.14.4 release See merge request nvidia/container-toolkit/container-toolkit!534
2 parents 53b2461 + cfe0d5d commit 29fd206

File tree

16 files changed

+249
-134
lines changed

16 files changed

+249
-134
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "third_party/libnvidia-container"]
22
path = third_party/libnvidia-container
33
url = https://gitlab.com/nvidia/container-toolkit/libnvidia-container.git
4-
branch = main
4+
branch = release-1.14

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# NVIDIA Container Toolkit Changelog
22

3+
## v1.14.4
4+
* Include `nvidia/nvoptix.bin` in list of graphics mounts.
5+
* Include `vulkan/icd.d/nvidia_layers.json` in list of graphics mounts.
6+
* Fixed bug in `nvidia-ctk config` command when using `--set`. The types of applied config options are now applied correctly.
7+
* Log explicitly requested runtime mode.
8+
* Remove package dependency on libseccomp.
9+
* Added detection of libnvdxgdmal.so.1 on WSL2.
10+
* Fix bug in determining default nvidia-container-runtime.user config value on SUSE-based systems.
11+
* Add `crun` to the list of configured low-level runtimes.
12+
13+
* [toolkit-container] Bump CUDA base image version to 12.3.1.
14+
* [libnvidia-container] Added detection of libnvdxgdmal.so.1 on WSL2.
15+
316
## v1.14.3
417
* [toolkit-container] Bump CUDA base image version to 12.2.2.
518

cmd/nvidia-ctk/config/config.go

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ package config
1919
import (
2020
"errors"
2121
"fmt"
22+
"reflect"
2223
"strconv"
2324
"strings"
2425

26+
"github.com/urfave/cli/v2"
27+
2528
createdefault "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/create-default"
2629
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/flags"
2730
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
2831
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
29-
"github.com/urfave/cli/v2"
3032
)
3133

3234
type command struct {
@@ -103,7 +105,7 @@ func run(c *cli.Context, opts *options) error {
103105
}
104106

105107
for _, set := range opts.sets.Value() {
106-
key, value, err := (*configToml)(cfgToml).setFlagToKeyValue(set)
108+
key, value, err := setFlagToKeyValue(set)
107109
if err != nil {
108110
return fmt.Errorf("invalid --set option %v: %w", set, err)
109111
}
@@ -126,50 +128,86 @@ func run(c *cli.Context, opts *options) error {
126128
return nil
127129
}
128130

129-
type configToml config.Toml
130-
131131
var errInvalidConfigOption = errors.New("invalid config option")
132+
var errUndefinedField = errors.New("undefined field")
132133
var errInvalidFormat = errors.New("invalid format")
133134

134135
// setFlagToKeyValue converts a --set flag to a key-value pair.
135136
// The set flag is of the form key[=value], with the value being optional if key refers to a
136137
// boolean config option.
137-
func (c *configToml) setFlagToKeyValue(setFlag string) (string, interface{}, error) {
138-
if c == nil {
139-
return "", nil, errInvalidConfigOption
140-
}
141-
138+
func setFlagToKeyValue(setFlag string) (string, interface{}, error) {
142139
setParts := strings.SplitN(setFlag, "=", 2)
143140
key := setParts[0]
144141

145-
v := (*config.Toml)(c).Get(key)
146-
if v == nil {
147-
return key, nil, errInvalidConfigOption
148-
}
149-
switch v.(type) {
150-
case bool:
151-
if len(setParts) == 1 {
152-
return key, true, nil
153-
}
142+
field, err := getField(key)
143+
if err != nil {
144+
return key, nil, fmt.Errorf("%w: %w", errInvalidConfigOption, err)
154145
}
155146

147+
kind := field.Kind()
156148
if len(setParts) != 2 {
149+
if kind == reflect.Bool {
150+
return key, true, nil
151+
}
157152
return key, nil, fmt.Errorf("%w: expected key=value; got %v", errInvalidFormat, setFlag)
158153
}
159154

160155
value := setParts[1]
161-
switch vt := v.(type) {
162-
case bool:
156+
switch kind {
157+
case reflect.Bool:
163158
b, err := strconv.ParseBool(value)
164159
if err != nil {
165160
return key, value, fmt.Errorf("%w: %w", errInvalidFormat, err)
166161
}
167162
return key, b, err
168-
case string:
163+
case reflect.String:
169164
return key, value, nil
170-
case []string:
171-
return key, strings.Split(value, ","), nil
172-
default:
173-
return key, nil, fmt.Errorf("unsupported type for %v (%v)", setParts, vt)
165+
case reflect.Slice:
166+
valueParts := strings.Split(value, ",")
167+
switch field.Elem().Kind() {
168+
case reflect.String:
169+
return key, valueParts, nil
170+
case reflect.Int:
171+
var output []int64
172+
for _, v := range valueParts {
173+
vi, err := strconv.ParseInt(v, 10, 0)
174+
if err != nil {
175+
return key, nil, fmt.Errorf("%w: %w", errInvalidFormat, err)
176+
}
177+
output = append(output, vi)
178+
}
179+
return key, output, nil
180+
}
181+
}
182+
return key, nil, fmt.Errorf("unsupported type for %v (%v)", setParts, kind)
183+
}
184+
185+
func getField(key string) (reflect.Type, error) {
186+
s, err := getStruct(reflect.TypeOf(config.Config{}), strings.Split(key, ".")...)
187+
if err != nil {
188+
return nil, err
189+
}
190+
return s.Type, err
191+
}
192+
193+
func getStruct(current reflect.Type, paths ...string) (reflect.StructField, error) {
194+
if len(paths) < 1 {
195+
return reflect.StructField{}, fmt.Errorf("%w: no fields selected", errUndefinedField)
196+
}
197+
tomlField := paths[0]
198+
for i := 0; i < current.NumField(); i++ {
199+
f := current.Field(i)
200+
v, ok := f.Tag.Lookup("toml")
201+
if !ok {
202+
continue
203+
}
204+
if v != tomlField {
205+
continue
206+
}
207+
if len(paths) == 1 {
208+
return f, nil
209+
}
210+
return getStruct(f.Type, paths[1:]...)
174211
}
212+
return reflect.StructField{}, fmt.Errorf("%w: %q", errUndefinedField, tomlField)
175213
}

cmd/nvidia-ctk/config/config_test.go

Lines changed: 44 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -19,152 +19,109 @@ package config
1919
import (
2020
"testing"
2121

22-
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
23-
"github.com/pelletier/go-toml"
2422
"github.com/stretchr/testify/require"
2523
)
2624

2725
func TestSetFlagToKeyValue(t *testing.T) {
26+
// TODO: We need to enable this test again since switching to reflect.
2827
testCases := []struct {
2928
description string
30-
config map[string]interface{}
3129
setFlag string
3230
expectedKey string
3331
expectedValue interface{}
3432
expectedError error
3533
}{
3634
{
37-
description: "empty config returns an error",
38-
setFlag: "anykey=value",
39-
expectedKey: "anykey",
35+
description: "option not present returns an error",
36+
setFlag: "undefined=new-value",
37+
expectedKey: "undefined",
4038
expectedError: errInvalidConfigOption,
4139
},
4240
{
43-
description: "option not present returns an error",
44-
config: map[string]interface{}{
45-
"defined": "defined-value",
46-
},
47-
setFlag: "undefined=new-value",
48-
expectedKey: "undefined",
41+
description: "undefined nexted option returns error",
42+
setFlag: "nvidia-container-cli.undefined",
43+
expectedKey: "nvidia-container-cli.undefined",
4944
expectedError: errInvalidConfigOption,
5045
},
5146
{
52-
description: "boolean option assumes true",
53-
config: map[string]interface{}{
54-
"boolean": false,
55-
},
56-
setFlag: "boolean",
57-
expectedKey: "boolean",
47+
description: "boolean option assumes true",
48+
setFlag: "disable-require",
49+
expectedKey: "disable-require",
5850
expectedValue: true,
5951
},
6052
{
61-
description: "boolean option returns true",
62-
config: map[string]interface{}{
63-
"boolean": false,
64-
},
65-
setFlag: "boolean=true",
66-
expectedKey: "boolean",
53+
description: "boolean option returns true",
54+
setFlag: "disable-require=true",
55+
expectedKey: "disable-require",
6756
expectedValue: true,
6857
},
6958
{
70-
description: "boolean option returns false",
71-
config: map[string]interface{}{
72-
"boolean": false,
73-
},
74-
setFlag: "boolean=false",
75-
expectedKey: "boolean",
59+
description: "boolean option returns false",
60+
setFlag: "disable-require=false",
61+
expectedKey: "disable-require",
7662
expectedValue: false,
7763
},
7864
{
79-
description: "invalid boolean option returns error",
80-
config: map[string]interface{}{
81-
"boolean": false,
82-
},
83-
setFlag: "boolean=something",
84-
expectedKey: "boolean",
65+
description: "invalid boolean option returns error",
66+
setFlag: "disable-require=something",
67+
expectedKey: "disable-require",
8568
expectedValue: "something",
8669
expectedError: errInvalidFormat,
8770
},
8871
{
89-
description: "string option requires value",
90-
config: map[string]interface{}{
91-
"string": "value",
92-
},
93-
setFlag: "string",
94-
expectedKey: "string",
72+
description: "string option requires value",
73+
setFlag: "swarm-resource",
74+
expectedKey: "swarm-resource",
9575
expectedValue: nil,
9676
expectedError: errInvalidFormat,
9777
},
9878
{
99-
description: "string option returns value",
100-
config: map[string]interface{}{
101-
"string": "value",
102-
},
103-
setFlag: "string=string-value",
104-
expectedKey: "string",
79+
description: "string option returns value",
80+
setFlag: "swarm-resource=string-value",
81+
expectedKey: "swarm-resource",
10582
expectedValue: "string-value",
10683
},
10784
{
108-
description: "string option returns value with equals",
109-
config: map[string]interface{}{
110-
"string": "value",
111-
},
112-
setFlag: "string=string-value=more",
113-
expectedKey: "string",
85+
description: "string option returns value with equals",
86+
setFlag: "swarm-resource=string-value=more",
87+
expectedKey: "swarm-resource",
11488
expectedValue: "string-value=more",
11589
},
11690
{
117-
description: "string option treats bool value as string",
118-
config: map[string]interface{}{
119-
"string": "value",
120-
},
121-
setFlag: "string=true",
122-
expectedKey: "string",
91+
description: "string option treats bool value as string",
92+
setFlag: "swarm-resource=true",
93+
expectedKey: "swarm-resource",
12394
expectedValue: "true",
12495
},
12596
{
126-
description: "string option treats int value as string",
127-
config: map[string]interface{}{
128-
"string": "value",
129-
},
130-
setFlag: "string=5",
131-
expectedKey: "string",
97+
description: "string option treats int value as string",
98+
setFlag: "swarm-resource=5",
99+
expectedKey: "swarm-resource",
132100
expectedValue: "5",
133101
},
134102
{
135-
description: "[]string option returns single value",
136-
config: map[string]interface{}{
137-
"string": []string{"value"},
138-
},
139-
setFlag: "string=string-value",
140-
expectedKey: "string",
103+
description: "[]string option returns single value",
104+
setFlag: "nvidia-container-cli.environment=string-value",
105+
expectedKey: "nvidia-container-cli.environment",
141106
expectedValue: []string{"string-value"},
142107
},
143108
{
144-
description: "[]string option returns multiple values",
145-
config: map[string]interface{}{
146-
"string": []string{"value"},
147-
},
148-
setFlag: "string=first,second",
149-
expectedKey: "string",
109+
description: "[]string option returns multiple values",
110+
setFlag: "nvidia-container-cli.environment=first,second",
111+
expectedKey: "nvidia-container-cli.environment",
150112
expectedValue: []string{"first", "second"},
151113
},
152114
{
153-
description: "[]string option returns values with equals",
154-
config: map[string]interface{}{
155-
"string": []string{"value"},
156-
},
157-
setFlag: "string=first=1,second=2",
158-
expectedKey: "string",
115+
description: "[]string option returns values with equals",
116+
setFlag: "nvidia-container-cli.environment=first=1,second=2",
117+
expectedKey: "nvidia-container-cli.environment",
159118
expectedValue: []string{"first=1", "second=2"},
160119
},
161120
}
162121

163122
for _, tc := range testCases {
164123
t.Run(tc.description, func(t *testing.T) {
165-
tree, _ := toml.TreeFromMap(tc.config)
166-
cfgToml := (*config.Toml)(tree)
167-
k, v, err := (*configToml)(cfgToml).setFlagToKeyValue(tc.setFlag)
124+
k, v, err := setFlagToKeyValue(tc.setFlag)
168125
require.ErrorIs(t, err, tc.expectedError)
169126
require.EqualValues(t, tc.expectedKey, k)
170127
require.EqualValues(t, tc.expectedValue, v)

0 commit comments

Comments
 (0)