Skip to content

Commit 37ee972

Browse files
author
Evan Lezar
committed
Merge branch 'CNT-2349/configure-docker' into 'main'
Add nvidia-ctk runtime configure command to update docker config See merge request nvidia/container-toolkit/container-toolkit!166
2 parents 3809407 + 9f0060f commit 37ee972

File tree

8 files changed

+642
-73
lines changed

8 files changed

+642
-73
lines changed

cmd/nvidia-ctk/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
# NVIDIA Container Toolkit CLI
22

33
The NVIDIA Container Toolkit CLI `nvidia-ctk` provides a number of utilities that are useful for working with the NVIDIA Container Toolkit.
4+
5+
## Functionality
6+
7+
### Configure runtimes
8+
9+
The `runtime` command of the `nvidia-ctk` CLI provides a set of utilities to related to the configuration
10+
and management of supported container engines.
11+
12+
For example, running the following command:
13+
```bash
14+
nvidia-ctk runtime configure --set-as-default
15+
```
16+
will ensure that the NVIDIA Container Runtime is added as the default runtime to the default container
17+
engine.

cmd/nvidia-ctk/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"os"
2121

2222
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook"
23+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime"
2324
"github.com/NVIDIA/nvidia-container-toolkit/internal/info"
2425
log "github.com/sirupsen/logrus"
2526
cli "github.com/urfave/cli/v2"
@@ -70,6 +71,7 @@ func main() {
7071
// Define the subcommands
7172
c.Commands = []*cli.Command{
7273
hook.NewCommand(logger),
74+
runtime.NewCommand(logger),
7375
}
7476

7577
// Run the CLI
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package configure
18+
19+
import (
20+
"encoding/json"
21+
"fmt"
22+
"os"
23+
24+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime/nvidia"
25+
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/docker"
26+
"github.com/sirupsen/logrus"
27+
"github.com/urfave/cli/v2"
28+
)
29+
30+
const (
31+
defaultRuntime = "docker"
32+
33+
defaultDockerConfigFilePath = "/etc/docker/daemon.json"
34+
)
35+
36+
type command struct {
37+
logger *logrus.Logger
38+
}
39+
40+
// NewCommand constructs an configure command with the specified logger
41+
func NewCommand(logger *logrus.Logger) *cli.Command {
42+
c := command{
43+
logger: logger,
44+
}
45+
return c.build()
46+
}
47+
48+
// config defines the options that can be set for the CLI through config files,
49+
// environment variables, or command line config
50+
type config struct {
51+
dryRun bool
52+
runtime string
53+
configFilePath string
54+
nvidiaOptions nvidia.Options
55+
}
56+
57+
func (m command) build() *cli.Command {
58+
// Create a config struct to hold the parsed environment variables or command line flags
59+
config := config{}
60+
61+
// Create the 'configure' command
62+
configure := cli.Command{
63+
Name: "configure",
64+
Usage: "Add a runtime to the specified container engine",
65+
Action: func(c *cli.Context) error {
66+
return m.configureWrapper(c, &config)
67+
},
68+
}
69+
70+
configure.Flags = []cli.Flag{
71+
&cli.BoolFlag{
72+
Name: "dry-run",
73+
Usage: "update the runtime configuration as required but don't write changes to disk",
74+
Destination: &config.dryRun,
75+
},
76+
&cli.StringFlag{
77+
Name: "runtime",
78+
Usage: "the target runtime engine. One of [docker]",
79+
Value: defaultRuntime,
80+
Destination: &config.runtime,
81+
},
82+
&cli.StringFlag{
83+
Name: "config",
84+
Usage: "path to the config file for the target runtime",
85+
Destination: &config.configFilePath,
86+
},
87+
&cli.StringFlag{
88+
Name: "nvidia-runtime-name",
89+
Usage: "specify the name of the NVIDIA runtime that will be added",
90+
Value: nvidia.RuntimeName,
91+
Destination: &config.nvidiaOptions.RuntimeName,
92+
},
93+
&cli.StringFlag{
94+
Name: "runtime-path",
95+
Usage: "specify the path to the NVIDIA runtime executable",
96+
Value: nvidia.RuntimeExecutable,
97+
Destination: &config.nvidiaOptions.RuntimePath,
98+
},
99+
&cli.BoolFlag{
100+
Name: "set-as-default",
101+
Usage: "set the specified runtime as the default runtime",
102+
Destination: &config.nvidiaOptions.SetAsDefault,
103+
},
104+
}
105+
106+
return &configure
107+
}
108+
109+
func (m command) configureWrapper(c *cli.Context, config *config) error {
110+
switch config.runtime {
111+
case "docker":
112+
return m.configureDocker(c, config)
113+
}
114+
115+
return fmt.Errorf("unrecognized runtime '%v'", config.runtime)
116+
}
117+
118+
// configureDocker updates the docker config to enable the NVIDIA Container Runtime
119+
func (m command) configureDocker(c *cli.Context, config *config) error {
120+
configFilePath := config.configFilePath
121+
if configFilePath == "" {
122+
configFilePath = defaultDockerConfigFilePath
123+
}
124+
125+
cfg, err := docker.LoadConfig(configFilePath)
126+
if err != nil {
127+
return fmt.Errorf("unable to load config: %v", err)
128+
}
129+
130+
defaultRuntime := config.nvidiaOptions.DefaultRuntime()
131+
runtimeConfig := config.nvidiaOptions.Runtime().DockerRuntimesConfig()
132+
err = docker.UpdateConfig(cfg, defaultRuntime, runtimeConfig)
133+
if err != nil {
134+
return fmt.Errorf("unable to update config: %v", err)
135+
}
136+
137+
if config.dryRun {
138+
output, err := json.MarshalIndent(cfg, "", " ")
139+
if err != nil {
140+
return fmt.Errorf("unable to convert to JSON: %v", err)
141+
}
142+
os.Stdout.WriteString(fmt.Sprintf("%s\n", output))
143+
return nil
144+
}
145+
err = docker.FlushConfig(cfg, configFilePath)
146+
if err != nil {
147+
return fmt.Errorf("unable to flush config: %v", err)
148+
}
149+
150+
m.logger.Infof("Wrote updated config to %v", configFilePath)
151+
m.logger.Infof("It is recommended that the docker daemon be restarted.")
152+
153+
return nil
154+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
*/
16+
17+
package nvidia
18+
19+
const (
20+
// RuntimeName is the default name to use in configs for the NVIDIA Container Runtime
21+
RuntimeName = "nvidia"
22+
// RuntimeExecutable is the default NVIDIA Container Runtime executable file name
23+
RuntimeExecutable = "nvidia-container-runtime"
24+
)
25+
26+
// Options specifies the options for the NVIDIA Container Runtime w.r.t a container engine such as docker.
27+
type Options struct {
28+
SetAsDefault bool
29+
RuntimeName string
30+
RuntimePath string
31+
}
32+
33+
// Runtime defines an NVIDIA runtime with a name and a executable
34+
type Runtime struct {
35+
Name string
36+
Path string
37+
}
38+
39+
// DefaultRuntime returns the default runtime for the configured options.
40+
// If the configuration is invalid or the default runtimes should not be set
41+
// the empty string is returned.
42+
func (o Options) DefaultRuntime() string {
43+
if !o.SetAsDefault {
44+
return ""
45+
}
46+
47+
return o.RuntimeName
48+
}
49+
50+
// Runtime creates a runtime struct based on the options.
51+
func (o Options) Runtime() Runtime {
52+
path := o.RuntimePath
53+
54+
if o.RuntimePath == "" {
55+
path = RuntimeExecutable
56+
}
57+
58+
r := Runtime{
59+
Name: o.RuntimeName,
60+
Path: path,
61+
}
62+
63+
return r
64+
}
65+
66+
// DockerRuntimesConfig generatest the expected docker config for the specified runtime
67+
func (r Runtime) DockerRuntimesConfig() map[string]interface{} {
68+
runtimes := make(map[string]interface{})
69+
runtimes[r.Name] = map[string]interface{}{
70+
"path": r.Path,
71+
"args": []string{},
72+
}
73+
74+
return runtimes
75+
}

cmd/nvidia-ctk/runtime/runtime.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package runtime
18+
19+
import (
20+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime/configure"
21+
"github.com/sirupsen/logrus"
22+
"github.com/urfave/cli/v2"
23+
)
24+
25+
type runtimeCommand struct {
26+
logger *logrus.Logger
27+
}
28+
29+
// NewCommand constructs a runtime command with the specified logger
30+
func NewCommand(logger *logrus.Logger) *cli.Command {
31+
c := runtimeCommand{
32+
logger: logger,
33+
}
34+
return c.build()
35+
}
36+
37+
func (m runtimeCommand) build() *cli.Command {
38+
// Create the 'runtime' command
39+
runtime := cli.Command{
40+
Name: "runtime",
41+
Usage: "A collection of runtime-related utilities for the NVIDIA Container Toolkit",
42+
}
43+
44+
runtime.Subcommands = []*cli.Command{
45+
configure.NewCommand(m.logger),
46+
}
47+
48+
return &runtime
49+
}

0 commit comments

Comments
 (0)