Skip to content

Commit 6b74ca6

Browse files
committed
fetch current container runtime config through the command line
Signed-off-by: Tariq Ibrahim <[email protected]> add default runtime binary path to runtimes field of toolkit config toml Signed-off-by: Tariq Ibrahim <[email protected]>
1 parent 19482da commit 6b74ca6

File tree

19 files changed

+449
-88
lines changed

19 files changed

+449
-88
lines changed

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ linters:
1818
linters-settings:
1919
goimports:
2020
local-prefixes: github.com/NVIDIA/nvidia-container-toolkit
21+
gosec:
22+
excludes:
23+
# TODO: Consider hardening security of command line invocations
24+
- G204
2125

2226
issues:
2327
exclude:

cmd/nvidia-ctk/runtime/configure/configure.go

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ const (
4444
defaultContainerdConfigFilePath = "/etc/containerd/config.toml"
4545
defaultCrioConfigFilePath = "/etc/crio/crio.conf"
4646
defaultDockerConfigFilePath = "/etc/docker/daemon.json"
47+
48+
defaultConfigSource = configSourceCommand
49+
configSourceCommand = "command"
50+
configSourceFile = "file"
51+
52+
runtimeContainerd = "containerd"
53+
runtimeCrio = "crio"
54+
runtimeDocker = "docker"
4755
)
4856

4957
type command struct {
@@ -64,6 +72,7 @@ type config struct {
6472
dryRun bool
6573
runtime string
6674
configFilePath string
75+
configSource string
6776
mode string
6877
hookFilePath string
6978

@@ -120,6 +129,12 @@ func (m command) build() *cli.Command {
120129
Usage: "the config mode for runtimes that support multiple configuration mechanisms",
121130
Destination: &config.mode,
122131
},
132+
&cli.StringFlag{
133+
Name: "config-source",
134+
Usage: "the source to retrieve the container runtime configuration",
135+
Destination: &config.configSource,
136+
Value: defaultConfigSource,
137+
},
123138
&cli.StringFlag{
124139
Name: "oci-hook-path",
125140
Usage: "the path to the OCI runtime hook to create if --config-mode=oci-hook is specified. If no path is specified, the generated hook is output to STDOUT.\n\tNote: The use of OCI hooks is deprecated.",
@@ -174,14 +189,14 @@ func (m command) validateFlags(c *cli.Context, config *config) error {
174189
config.mode = "config-file"
175190

176191
switch config.runtime {
177-
case "containerd", "crio", "docker":
192+
case runtimeContainerd, runtimeCrio, runtimeDocker:
178193
break
179194
default:
180195
return fmt.Errorf("unrecognized runtime '%v'", config.runtime)
181196
}
182197

183198
switch config.runtime {
184-
case "containerd", "crio":
199+
case runtimeContainerd, runtimeCrio:
185200
if config.nvidiaRuntime.path == defaultNVIDIARuntimeExecutable {
186201
config.nvidiaRuntime.path = defaultNVIDIARuntimeExpecutablePath
187202
}
@@ -190,7 +205,7 @@ func (m command) validateFlags(c *cli.Context, config *config) error {
190205
}
191206
}
192207

193-
if config.runtime != "containerd" && config.runtime != "docker" {
208+
if config.runtime != runtimeContainerd && config.runtime != runtimeDocker {
194209
if config.cdi.enabled {
195210
m.logger.Warningf("Ignoring cdi.enabled flag for %v", config.runtime)
196211
}
@@ -220,22 +235,27 @@ func (m command) configureWrapper(c *cli.Context, config *config) error {
220235
func (m command) configureConfigFile(c *cli.Context, config *config) error {
221236
configFilePath := config.resolveConfigFilePath()
222237

223-
var cfg engine.Interface
224238
var err error
239+
configSource, err := config.resolveConfigSource()
240+
if err != nil {
241+
return err
242+
}
243+
244+
var cfg engine.Interface
225245
switch config.runtime {
226-
case "containerd":
246+
case runtimeContainerd:
227247
cfg, err = containerd.New(
228248
containerd.WithLogger(m.logger),
229249
containerd.WithPath(configFilePath),
230-
containerd.WithConfigSource(toml.FromFile(configFilePath)),
250+
containerd.WithConfigSource(configSource),
231251
)
232-
case "crio":
252+
case runtimeCrio:
233253
cfg, err = crio.New(
234254
crio.WithLogger(m.logger),
235255
crio.WithPath(configFilePath),
236-
crio.WithConfigSource(toml.FromFile(configFilePath)),
256+
crio.WithConfigSource(configSource),
237257
)
238-
case "docker":
258+
case runtimeDocker:
239259
cfg, err = docker.New(
240260
docker.WithLogger(m.logger),
241261
docker.WithPath(configFilePath),
@@ -285,16 +305,41 @@ func (c *config) resolveConfigFilePath() string {
285305
return c.configFilePath
286306
}
287307
switch c.runtime {
288-
case "containerd":
308+
case runtimeContainerd:
289309
return defaultContainerdConfigFilePath
290-
case "crio":
310+
case runtimeCrio:
291311
return defaultCrioConfigFilePath
292-
case "docker":
312+
case runtimeDocker:
293313
return defaultDockerConfigFilePath
294314
}
295315
return ""
296316
}
297317

318+
// resolveConfigSource returns the default config source or the user provided config source
319+
func (c *config) resolveConfigSource() (toml.Loader, error) {
320+
switch c.configSource {
321+
case configSourceCommand:
322+
323+
cmd := c.getConfigSourceCommand()
324+
return toml.FromCommandLine(cmd), nil
325+
case configSourceFile:
326+
return toml.FromFile(c.configFilePath), nil
327+
default:
328+
return nil, fmt.Errorf("unrecognized config source: %s", c.configSource)
329+
}
330+
}
331+
332+
// getConfigSourceCommand returns the default cli command to fetch the current runtime config
333+
func (c *config) getConfigSourceCommand() []string {
334+
switch c.runtime {
335+
case runtimeContainerd:
336+
return []string{"containerd", "config", "dump"}
337+
case runtimeCrio:
338+
return []string{"crio", "status", "config"}
339+
}
340+
return []string{}
341+
}
342+
298343
// getOuputConfigPath returns the configured config path or "" if dry-run is enabled
299344
func (c *config) getOuputConfigPath() string {
300345
if c.dryRun {
@@ -318,9 +363,9 @@ func enableCDI(config *config, cfg engine.Interface) error {
318363
return nil
319364
}
320365
switch config.runtime {
321-
case "containerd":
366+
case runtimeContainerd:
322367
cfg.Set("enable_cdi", true)
323-
case "docker":
368+
case runtimeDocker:
324369
cfg.Set("features", map[string]bool{"cdi": true})
325370
default:
326371
return fmt.Errorf("enabling CDI in %s is not supported", config.runtime)

internal/config/toml.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,26 @@ func (t *Toml) Get(key string) interface{} {
170170
return (*toml.Tree)(t).Get(key)
171171
}
172172

173+
// GetDefault returns the value for the specified key and falls back to the default value if the Get call fails
174+
func (t *Toml) GetDefault(key string, def interface{}) interface{} {
175+
val := t.Get(key)
176+
if val == nil {
177+
return def
178+
}
179+
return val
180+
}
181+
173182
// Set sets the specified key to the specified value in the TOML config.
174183
func (t *Toml) Set(key string, value interface{}) {
175184
(*toml.Tree)(t).Set(key, value)
176185
}
177186

187+
// WriteTo encode the Tree as Toml and writes it to the writer w.
188+
// Returns the number of bytes written in case of success, or an error if anything happened.
189+
func (t *Toml) WriteTo(w io.Writer) (int64, error) {
190+
return (*toml.Tree)(t).WriteTo(w)
191+
}
192+
178193
// commentDefaults applies the required comments for default values to the Toml.
179194
func (t *Toml) commentDefaults() *Toml {
180195
asToml := (*toml.Tree)(t)

pkg/config/engine/api.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,10 @@ type Interface interface {
2323
Set(string, interface{})
2424
RemoveRuntime(string) error
2525
Save(string) (int64, error)
26+
GetRuntimeConfig(string) (RuntimeConfig, error)
27+
}
28+
29+
// RuntimeConfig defines the interface to query container runtime handler configuration
30+
type RuntimeConfig interface {
31+
GetBinPath() string
2632
}

pkg/config/engine/containerd/config_v1.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,25 @@ import (
2222
"github.com/pelletier/go-toml"
2323

2424
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
25+
cfgtoml "github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
2526
)
2627

2728
// ConfigV1 represents a version 1 containerd config
2829
type ConfigV1 Config
2930

3031
var _ engine.Interface = (*ConfigV1)(nil)
3132

33+
type ctrdCfgV1Runtime struct {
34+
tree *cfgtoml.Tree
35+
}
36+
37+
func (c *ctrdCfgV1Runtime) GetBinPath() string {
38+
if binPath, ok := c.tree.GetPath([]string{"options", "BinaryName"}).(string); ok {
39+
return binPath
40+
}
41+
return ""
42+
}
43+
3244
// AddRuntime adds a runtime to the containerd config
3345
func (c *ConfigV1) AddRuntime(name string, path string, setAsDefault bool) error {
3446
if c == nil || c.Tree == nil {
@@ -146,6 +158,18 @@ func (c *ConfigV1) RemoveRuntime(name string) error {
146158
return nil
147159
}
148160

161+
func (c *ConfigV1) GetRuntime(name string) (interface{}, error) {
162+
if c == nil || c.Tree == nil {
163+
return nil, fmt.Errorf("config is nil")
164+
}
165+
config := *c.Tree
166+
runtimeData, ok := config.GetPath([]string{"plugins", "cri", "containerd", "runtimes", name}).(*toml.Tree)
167+
if !ok {
168+
return nil, fmt.Errorf("invalid toml object")
169+
}
170+
return runtimeData, nil
171+
}
172+
149173
// SetOption sets the specified containerd option.
150174
func (c *ConfigV1) Set(key string, value interface{}) {
151175
config := *c.Tree
@@ -157,3 +181,15 @@ func (c *ConfigV1) Set(key string, value interface{}) {
157181
func (c ConfigV1) Save(path string) (int64, error) {
158182
return (Config)(c).Save(path)
159183
}
184+
185+
func (c *ConfigV1) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
186+
if c == nil || c.Tree == nil {
187+
return nil, fmt.Errorf("config is nil")
188+
}
189+
config := *c.Tree
190+
runtimeData := config.GetSubtreeByPath([]string{"plugins", "cri", "containerd", "runtimes", name})
191+
192+
return &ctrdCfgV1Runtime{
193+
tree: runtimeData,
194+
}, nil
195+
}

pkg/config/engine/containerd/config_v2.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ import (
2222
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
2323
)
2424

25+
type ctrdCfgV2Runtime struct {
26+
tree *toml.Tree
27+
}
28+
29+
func (c *ctrdCfgV2Runtime) GetBinPath() string {
30+
if binPath, ok := c.tree.GetPath([]string{"options", "BinaryName"}).(string); ok {
31+
return binPath
32+
}
33+
return ""
34+
}
35+
2536
// AddRuntime adds a runtime to the containerd config
2637
func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error {
2738
if c == nil || c.Tree == nil {

pkg/config/engine/containerd/containerd.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,14 @@ func (c *Config) parseVersion(useLegacyConfig bool) (int, error) {
9898
return -1, fmt.Errorf("unsupported type for version field: %v", v)
9999
}
100100
}
101+
102+
func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
103+
if c == nil || c.Tree == nil {
104+
return nil, fmt.Errorf("config is nil")
105+
}
106+
config := *c.Tree
107+
runtimeData := config.GetSubtreeByPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name})
108+
return &ctrdCfgV2Runtime{
109+
tree: runtimeData,
110+
}, nil
111+
}

pkg/config/engine/crio/crio.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ type Config struct {
3030
Logger logger.Interface
3131
}
3232

33+
type crioRuntime struct {
34+
tree *toml.Tree
35+
}
36+
37+
func (c *crioRuntime) GetBinPath() string {
38+
if binaryPath, ok := c.tree.GetPath([]string{"runtime_path"}).(string); ok && binaryPath != "" {
39+
return binaryPath
40+
}
41+
return ""
42+
}
43+
3344
var _ engine.Interface = (*Config)(nil)
3445

3546
// New creates a cri-o config with the specified options
@@ -66,10 +77,11 @@ func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error {
6677
config := *c.Tree
6778

6879
// By default we extract the runtime options from the runc settings; if this does not exist we get the options from the default runtime specified in the config.
69-
runtimeNamesForConfig := []string{"runc"}
80+
var runtimeNamesForConfig []string
7081
if name, ok := config.GetPath([]string{"crio", "runtime", "default_runtime"}).(string); ok && name != "" {
7182
runtimeNamesForConfig = append(runtimeNamesForConfig, name)
7283
}
84+
runtimeNamesForConfig = append(runtimeNamesForConfig, "runc")
7385
for _, r := range runtimeNamesForConfig {
7486
if options, ok := config.GetPath([]string{"crio", "runtime", "runtimes", r}).(*toml.Tree); ok {
7587
c.Logger.Debugf("using options from runtime %v: %v", r, options.String())
@@ -129,3 +141,14 @@ func (c *Config) RemoveRuntime(name string) error {
129141
*c.Tree = config
130142
return nil
131143
}
144+
145+
func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
146+
if c == nil || c.Tree == nil {
147+
return nil, fmt.Errorf("config is nil")
148+
}
149+
config := *c.Tree
150+
runtimeData := config.GetSubtreeByPath([]string{"crio", "runtime", "runtimes", name})
151+
return &crioRuntime{
152+
tree: runtimeData,
153+
}, nil
154+
}

pkg/config/engine/crio/crio_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func TestAddRuntime(t *testing.T) {
9191
`,
9292
},
9393
{
94-
description: "options from runc take precedence over default runtime",
94+
description: "options from runc DO NOT take precedence over default runtime",
9595
config: `
9696
[crio]
9797
[crio.runtime]
@@ -120,7 +120,7 @@ func TestAddRuntime(t *testing.T) {
120120
[crio.runtime.runtimes.test]
121121
runtime_path = "/usr/bin/test"
122122
runtime_type = "oci"
123-
runc_option = "option"
123+
default_option = "option"
124124
`,
125125
},
126126
}

pkg/config/engine/docker/docker.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package docker
1818

1919
import (
2020
"encoding/json"
21+
"errors"
2122
"fmt"
2223

2324
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
@@ -132,3 +133,29 @@ func (c Config) Save(path string) (int64, error) {
132133
n, err := config.Raw(path).Write(output)
133134
return int64(n), err
134135
}
136+
137+
// GetRuntime returns the TOML object of the runtime passed as input
138+
func (c *Config) GetRuntime(name string) (interface{}, error) {
139+
if c == nil {
140+
return nil, fmt.Errorf("config is nil")
141+
}
142+
143+
config := *c
144+
145+
var runtimes map[string]interface{}
146+
if _, exists := config["runtimes"]; exists {
147+
runtimes = config["runtimes"].(map[string]interface{})
148+
} else {
149+
return nil, fmt.Errorf("config is nil")
150+
}
151+
152+
if r, ok := runtimes[name]; ok {
153+
return r, nil
154+
} else {
155+
return nil, fmt.Errorf("runtime %s not found", name)
156+
}
157+
}
158+
159+
func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
160+
return nil, errors.New("Not Implemented")
161+
}

0 commit comments

Comments
 (0)