Skip to content

Commit cdc878b

Browse files
committed
move nvidia-ctk hook command into own binary
Signed-off-by: Avi Deitcher <[email protected]>
1 parent a442a5e commit cdc878b

36 files changed

+387
-195
lines changed

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.

cmd/nvidia-cdi-hook/main.go

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

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
package hook
1818

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

2323
"github.com/urfave/cli/v2"
2424

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"
25+
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/create-symlinks"
26+
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/update-ldcache"
2727
)
2828

2929
type hookCommand struct {

internal/config/config.go

+19-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"
@@ -186,6 +187,22 @@ func ResolveNVIDIACTKPath(logger logger.Interface, nvidiaCTKPath string) string
186187
)
187188
}
188189

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

internal/discover/graphics.go

+25-25
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@ import (
3636
// TODO: The logic for creating DRM devices should be consolidated between this
3737
// and the logic for generating CDI specs for a single device. This is only used
3838
// when applying OCI spec modifications to an incoming spec in "legacy" mode.
39-
func NewDRMNodesDiscoverer(logger logger.Interface, devices image.VisibleDevices, devRoot string, nvidiaCTKPath string) (Discover, error) {
39+
func NewDRMNodesDiscoverer(logger logger.Interface, devices image.VisibleDevices, devRoot string, nvidiaCDIHookPath string) (Discover, error) {
4040
drmDeviceNodes, err := newDRMDeviceDiscoverer(logger, devices, devRoot)
4141
if err != nil {
4242
return nil, fmt.Errorf("failed to create DRM device discoverer: %v", err)
4343
}
4444

45-
drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, devRoot, nvidiaCTKPath)
45+
drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, devRoot, nvidiaCDIHookPath)
4646

4747
discover := Merge(drmDeviceNodes, drmByPathSymlinks)
4848
return discover, nil
4949
}
5050

5151
// NewGraphicsMountsDiscoverer creates a discoverer for the mounts required by graphics tools such as vulkan.
52-
func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) (Discover, error) {
52+
func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCDIHookPath string) (Discover, error) {
5353
libraries := NewMounts(
5454
logger,
5555
driver.Libraries(),
@@ -74,7 +74,7 @@ func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, n
7474
},
7575
)
7676

77-
xorg := optionalXorgDiscoverer(logger, driver, nvidiaCTKPath)
77+
xorg := optionalXorgDiscoverer(logger, driver, nvidiaCDIHookPath)
7878

7979
discover := Merge(
8080
libraries,
@@ -87,19 +87,19 @@ func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, n
8787

8888
type drmDevicesByPath struct {
8989
None
90-
logger logger.Interface
91-
nvidiaCTKPath string
92-
devRoot string
93-
devicesFrom Discover
90+
logger logger.Interface
91+
nvidiaCDIHookPath string
92+
devRoot string
93+
devicesFrom Discover
9494
}
9595

9696
// newCreateDRMByPathSymlinks creates a discoverer for a hook to create the by-path symlinks for DRM devices discovered by the specified devices discoverer
97-
func newCreateDRMByPathSymlinks(logger logger.Interface, devices Discover, devRoot string, nvidiaCTKPath string) Discover {
97+
func newCreateDRMByPathSymlinks(logger logger.Interface, devices Discover, devRoot string, nvidiaCDIHookPath string) Discover {
9898
d := drmDevicesByPath{
99-
logger: logger,
100-
nvidiaCTKPath: nvidiaCTKPath,
101-
devRoot: devRoot,
102-
devicesFrom: devices,
99+
logger: logger,
100+
nvidiaCDIHookPath: nvidiaCDIHookPath,
101+
devRoot: devRoot,
102+
devicesFrom: devices,
103103
}
104104

105105
return &d
@@ -127,8 +127,8 @@ func (d drmDevicesByPath) Hooks() ([]Hook, error) {
127127
args = append(args, "--link", l)
128128
}
129129

130-
hook := CreateNvidiaCTKHook(
131-
d.nvidiaCTKPath,
130+
hook := CreateNvidiaCDIHook(
131+
d.nvidiaCDIHookPath,
132132
"create-symlinks",
133133
args...,
134134
)
@@ -233,25 +233,25 @@ func newDRMDeviceFilter(devices image.VisibleDevices, devRoot string) (Filter, e
233233
}
234234

235235
type xorgHooks struct {
236-
libraries Discover
237-
driverVersion string
238-
nvidiaCTKPath string
236+
libraries Discover
237+
driverVersion string
238+
nvidiaCDIHookPath string
239239
}
240240

241241
var _ Discover = (*xorgHooks)(nil)
242242

243243
// optionalXorgDiscoverer creates a discoverer for Xorg libraries.
244244
// If the creation of the discoverer fails, a None discoverer is returned.
245-
func optionalXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) Discover {
246-
xorg, err := newXorgDiscoverer(logger, driver, nvidiaCTKPath)
245+
func optionalXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCDIHookPath string) Discover {
246+
xorg, err := newXorgDiscoverer(logger, driver, nvidiaCDIHookPath)
247247
if err != nil {
248248
logger.Warningf("Failed to create Xorg discoverer: %v; skipping xorg libraries", err)
249249
return None{}
250250
}
251251
return xorg
252252
}
253253

254-
func newXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) (Discover, error) {
254+
func newXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCDIHookPath string) (Discover, error) {
255255
libCudaPaths, err := cuda.New(
256256
driver.Libraries(),
257257
).Locate(".*.*")
@@ -281,9 +281,9 @@ func newXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPa
281281
},
282282
)
283283
xorgHooks := xorgHooks{
284-
libraries: xorgLibs,
285-
driverVersion: version,
286-
nvidiaCTKPath: nvidiaCTKPath,
284+
libraries: xorgLibs,
285+
driverVersion: version,
286+
nvidiaCDIHookPath: nvidiaCDIHookPath,
287287
}
288288

289289
xorgConfig := NewMounts(
@@ -332,7 +332,7 @@ func (m xorgHooks) Hooks() ([]Hook, error) {
332332
link := strings.TrimSuffix(target, "."+m.driverVersion)
333333
links := []string{fmt.Sprintf("%s::%s", filepath.Base(target), link)}
334334
symlinkHook := CreateCreateSymlinkHook(
335-
m.nvidiaCTKPath,
335+
m.nvidiaCDIHookPath,
336336
links,
337337
)
338338

0 commit comments

Comments
 (0)