Skip to content

Commit 179d865

Browse files
deitchelezar
authored andcommitted
Move nvidia-ctk hook command into own binary
This change creates an nvidia-cdi-hook binary for implementing CDI hooks. This allows for these hooks to be separated from the nvidia-ctk command which may, for example, require libnvidia-ml to support other functionality. The nvidia-ctk hook subcommand is maintained as an alias for the time being to allow for existing CDI specifications referring to this path to work as expected. Signed-off-by: Avi Deitcher <[email protected]>
1 parent 2d7b236 commit 179d865

39 files changed

+431
-206
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# NVIDIA Container Toolkit Changelog
22

3+
* Move `nvidia-ctk hook` commands to a separate `nvidia-cdi-hook` binary. The same subcommands are supported.
4+
35
## v1.15.0
46

57
* Remove `nvidia-container-runtime` and `nvidia-docker2` packages.

cmd/nvidia-cdi-hook/README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# NVIDIA CDI Hook
2+
3+
The CLI `nvidia-cdi-hook` provides container device runtime hook capabilities when
4+
called by a container runtime, as specific in a
5+
[Container Device Interface](https://tags.cncf.io/container-device-interface/blob/main/SPEC.md)
6+
file.
7+
8+
## Generating a CDI
9+
10+
The CDI itself is created for an NVIDIA-capable device using the
11+
[`nvidia-ctk cdi generate`](../nvidia-ctk/) command.
12+
13+
When `nvidia-ctk cdi generate` is run, the CDI specification is generated as a yaml file.
14+
The CDI specification provides instructions for a container runtime to set up devices, files and
15+
other resources for the container prior to starting it. Those instructions
16+
may include executing command-line tools to prepare the filesystem. The execution
17+
of such command-line tools is called a hook.
18+
19+
`nvidia-cdi-hook` is the CLI tool that is expected to be called by the container runtime,
20+
when specified by the CDI file.
21+
22+
See the [`nvidia-ctk` documentation](../nvidia-ctk/README.md) for more information
23+
on generating a CDI file.
24+
25+
## Functionality
26+
27+
The `nvidia-cdi-hook` CLI provides the following functionality:
28+
29+
* `chmod` - Change the permissions of a file or directory inside the directory path to be mounted into a container.
30+
* `create-symlinks` - Create symlinks inside the directory path to be mounted into a container.
31+
* `update-ldcache` - Update the dynamic linker cache inside the directory path to be mounted into a container.
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
# Copyright 2024 NVIDIA CORPORATION
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 commands
18+
19+
import (
20+
"github.com/urfave/cli/v2"
21+
22+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/chmod"
23+
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/create-symlinks"
24+
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/update-ldcache"
25+
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
26+
)
27+
28+
// New creates the commands associated with supported CDI hooks.
29+
// These are shared by the nvidia-cdi-hook and nvidia-ctk hook commands.
30+
func New(logger logger.Interface) []*cli.Command {
31+
return []*cli.Command{
32+
ldcache.NewCommand(logger),
33+
symlinks.NewCommand(logger),
34+
chmod.NewCommand(logger),
35+
}
36+
}

cmd/nvidia-cdi-hook/main.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
# Copyright (c) 2024, 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 main
18+
19+
import (
20+
"os"
21+
22+
"github.com/sirupsen/logrus"
23+
24+
"github.com/NVIDIA/nvidia-container-toolkit/internal/info"
25+
26+
cli "github.com/urfave/cli/v2"
27+
28+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/commands"
29+
)
30+
31+
// options defines the options that can be set for the CLI through config files,
32+
// environment variables, or command line flags
33+
type options struct {
34+
// Debug indicates whether the CLI is started in "debug" mode
35+
Debug bool
36+
// Quiet indicates whether the CLI is started in "quiet" mode
37+
Quiet bool
38+
}
39+
40+
func main() {
41+
logger := logrus.New()
42+
43+
// Create a options struct to hold the parsed environment variables or command line flags
44+
opts := options{}
45+
46+
// Create the top-level CLI
47+
c := cli.NewApp()
48+
c.Name = "NVIDIA CDI Hook"
49+
c.UseShortOptionHandling = true
50+
c.EnableBashCompletion = true
51+
c.Usage = "Command to structure files for usage inside a container, called as hooks from a container runtime, defined in a CDI yaml file"
52+
c.Version = info.GetVersionString()
53+
54+
// Setup the flags for this command
55+
c.Flags = []cli.Flag{
56+
&cli.BoolFlag{
57+
Name: "debug",
58+
Aliases: []string{"d"},
59+
Usage: "Enable debug-level logging",
60+
Destination: &opts.Debug,
61+
EnvVars: []string{"NVIDIA_CDI_DEBUG"},
62+
},
63+
&cli.BoolFlag{
64+
Name: "quiet",
65+
Usage: "Suppress all output except for errors; overrides --debug",
66+
Destination: &opts.Quiet,
67+
EnvVars: []string{"NVIDIA_CDI_QUIET"},
68+
},
69+
}
70+
71+
// Set log-level for all subcommands
72+
c.Before = func(c *cli.Context) error {
73+
logLevel := logrus.InfoLevel
74+
if opts.Debug {
75+
logLevel = logrus.DebugLevel
76+
}
77+
if opts.Quiet {
78+
logLevel = logrus.ErrorLevel
79+
}
80+
logger.SetLevel(logLevel)
81+
return nil
82+
}
83+
84+
// Define the subcommands
85+
c.Commands = commands.New(logger)
86+
87+
// Run the CLI
88+
err := c.Run(os.Args)
89+
if err != nil {
90+
logger.Errorf("%v", err)
91+
os.Exit(1)
92+
}
93+
}

cmd/nvidia-ctk/cdi/generate/generate.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type options struct {
4747
deviceNameStrategies cli.StringSlice
4848
driverRoot string
4949
devRoot string
50-
nvidiaCTKPath string
50+
nvidiaCDIHookPath string
5151
ldconfigPath string
5252
mode string
5353
vendor string
@@ -132,9 +132,12 @@ func (m command) build() *cli.Command {
132132
Destination: &opts.librarySearchPaths,
133133
},
134134
&cli.StringFlag{
135-
Name: "nvidia-ctk-path",
136-
Usage: "Specify the path to use for the nvidia-ctk in the generated CDI specification. If this is left empty, the path will be searched.",
137-
Destination: &opts.nvidiaCTKPath,
135+
Name: "nvidia-cdi-hook-path",
136+
Aliases: []string{"nvidia-ctk-path"},
137+
Usage: "Specify the path to use for the nvidia-cdi-hook in the generated CDI specification. " +
138+
"If not specified, the PATH will be searched for `nvidia-cdi-hook`. " +
139+
"NOTE: That if this is specified as `nvidia-ctk`, the PATH will be searched for `nvidia-ctk` instead.",
140+
Destination: &opts.nvidiaCDIHookPath,
138141
},
139142
&cli.StringFlag{
140143
Name: "ldconfig-path",
@@ -198,7 +201,7 @@ func (m command) validateFlags(c *cli.Context, opts *options) error {
198201
}
199202
}
200203

201-
opts.nvidiaCTKPath = config.ResolveNVIDIACTKPath(m.logger, opts.nvidiaCTKPath)
204+
opts.nvidiaCDIHookPath = config.ResolveNVIDIACDIHookPath(m.logger, opts.nvidiaCDIHookPath)
202205

203206
if outputFileFormat := formatFromFilename(opts.output); outputFileFormat != "" {
204207
m.logger.Debugf("Inferred output format as %q from output file name", outputFileFormat)
@@ -262,7 +265,7 @@ func (m command) generateSpec(opts *options) (spec.Interface, error) {
262265
nvcdi.WithLogger(m.logger),
263266
nvcdi.WithDriverRoot(opts.driverRoot),
264267
nvcdi.WithDevRoot(opts.devRoot),
265-
nvcdi.WithNVIDIACTKPath(opts.nvidiaCTKPath),
268+
nvcdi.WithNVIDIACDIHookPath(opts.nvidiaCDIHookPath),
266269
nvcdi.WithLdconfigPath(opts.ldconfigPath),
267270
nvcdi.WithDeviceNamers(deviceNamers...),
268271
nvcdi.WithMode(opts.mode),

cmd/nvidia-ctk/hook/hook.go

+2-9
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@
1717
package hook
1818

1919
import (
20-
chmod "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/chmod"
20+
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/commands"
2121
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
2222

2323
"github.com/urfave/cli/v2"
24-
25-
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/create-symlinks"
26-
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/update-ldcache"
2724
)
2825

2926
type hookCommand struct {
@@ -46,11 +43,7 @@ func (m hookCommand) build() *cli.Command {
4643
Usage: "A collection of hooks that may be injected into an OCI spec",
4744
}
4845

49-
hook.Subcommands = []*cli.Command{
50-
ldcache.NewCommand(m.logger),
51-
symlinks.NewCommand(m.logger),
52-
chmod.NewCommand(m.logger),
53-
}
46+
hook.Subcommands = commands.New(m.logger)
5447

5548
return &hook
5649
}

internal/config/config.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ const (
3333
configOverride = "XDG_CONFIG_HOME"
3434
configFilePath = "nvidia-container-runtime/config.toml"
3535

36-
nvidiaCTKExecutable = "nvidia-ctk"
37-
nvidiaCTKDefaultFilePath = "/usr/bin/nvidia-ctk"
36+
nvidiaCTKExecutable = "nvidia-ctk"
37+
nvidiaCTKDefaultFilePath = "/usr/bin/nvidia-ctk"
38+
nvidiaCDIHookDefaultFilePath = "/usr/bin/nvidia-cdi-hook"
3839

3940
nvidiaContainerRuntimeHookExecutable = "nvidia-container-runtime-hook"
4041
nvidiaContainerRuntimeHookDefaultPath = "/usr/bin/nvidia-container-runtime-hook"
@@ -177,6 +178,8 @@ var getDistIDLike = func() []string {
177178
// This executable is used in hooks and needs to be an absolute path.
178179
// If the path is specified as an absolute path, it is used directly
179180
// without checking for existence of an executable at that path.
181+
//
182+
// Deprecated: Use ResolveNVIDIACDIHookPath directly instead.
180183
func ResolveNVIDIACTKPath(logger logger.Interface, nvidiaCTKPath string) string {
181184
return resolveWithDefault(
182185
logger,
@@ -186,6 +189,27 @@ func ResolveNVIDIACTKPath(logger logger.Interface, nvidiaCTKPath string) string
186189
)
187190
}
188191

192+
// ResolveNVIDIACDIHookPath resolves the path to the nvidia-cdi-hook binary.
193+
// This executable is used in hooks and needs to be an absolute path.
194+
// If the path is specified as an absolute path, it is used directly
195+
// without checking for existence of an executable at that path.
196+
func ResolveNVIDIACDIHookPath(logger logger.Interface, nvidiaCDIHookPath string) string {
197+
if filepath.Base(nvidiaCDIHookPath) == "nvidia-ctk" {
198+
return resolveWithDefault(
199+
logger,
200+
"NVIDIA Container Toolkit CLI",
201+
nvidiaCDIHookPath,
202+
nvidiaCTKDefaultFilePath,
203+
)
204+
}
205+
return resolveWithDefault(
206+
logger,
207+
"NVIDIA CDI Hook CLI",
208+
nvidiaCDIHookPath,
209+
nvidiaCDIHookDefaultFilePath,
210+
)
211+
}
212+
189213
// ResolveNVIDIAContainerRuntimeHookPath resolves the path the nvidia-container-runtime-hook binary.
190214
func ResolveNVIDIAContainerRuntimeHookPath(logger logger.Interface, nvidiaContainerRuntimeHookPath string) string {
191215
return resolveWithDefault(

0 commit comments

Comments
 (0)