Skip to content

Commit fe90b00

Browse files
authored
Merge pull request #1308 from ArangoGutierrez/i1225
Fix handling of unrecognised CDI hooks
2 parents f5b4c15 + c258ca7 commit fe90b00

File tree

3 files changed

+75
-40
lines changed

3 files changed

+75
-40
lines changed

cmd/nvidia-cdi-hook/commands/commands.go

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package commands
1818

1919
import (
20+
"context"
21+
"strings"
22+
2023
"github.com/urfave/cli/v3"
2124

2225
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/chmod"
@@ -27,27 +30,89 @@ import (
2730
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
2831
)
2932

30-
// New creates the commands associated with supported CDI hooks.
31-
// These are shared by the nvidia-cdi-hook and nvidia-ctk hook commands.
32-
func New(logger logger.Interface) []*cli.Command {
33-
return []*cli.Command{
33+
// ConfigureCDIHookCommand configures a base command with supported CDI hooks
34+
// and error handling for unsupported hooks.
35+
// This allows the same command to be used for the nvidia-cdi-hook and
36+
// nvidia-ctk hook commands.
37+
func ConfigureCDIHookCommand(logger logger.Interface, base *cli.Command) *cli.Command {
38+
// We set the default action for the command to issue a warning and exit
39+
// with no error.
40+
// This means that if an unsupported hook is run, a container will not fail
41+
// to launch. An unsupported hook could be the result of a CDI specification
42+
// referring to a new hook that is not yet supported by an older NVIDIA
43+
// Container Toolkit version or a hook that has been removed in newer
44+
// version.
45+
base.Action = func(ctx context.Context, cmd *cli.Command) error {
46+
return issueUnsupportedHookWarning(logger, cmd)
47+
}
48+
// CommandNotFound is triggered when an unrecognised (sub)command is detected.
49+
// We assume that an unrecognised (sub)command represents an unsupported hook
50+
// (usually a hook that was added or removed)
51+
base.CommandNotFound = func(ctx context.Context, cmd *cli.Command, commandName string) {
52+
_ = issueUnsupportedHookWarning(logger, cmd)
53+
}
54+
// OnUsageError is triggered when an unexpected flag is detected.
55+
// We check the invoked command to determine whether it is an expected
56+
// hook, and assume that this is an unsupported hook otherwise.
57+
base.OnUsageError = func(ctx context.Context, cmd *cli.Command, err error, isSubcommand bool) error {
58+
// If this is not an error that comes from parsing an unrecognised flag,
59+
// return it as is.
60+
if !strings.HasPrefix(err.Error(), "flag provided but not defined: -") {
61+
return err
62+
}
63+
64+
// If the first argument is a recognised command, we return the error as
65+
// is since it represents an incorrect argument to the specific hook.
66+
var subcommandName string
67+
for _, arg := range cmd.Args().Slice() {
68+
if strings.HasPrefix(arg, "-") {
69+
continue
70+
}
71+
subcommandName = arg
72+
break
73+
}
74+
// If a subcommand is detected and is a recognised subcommand, we return
75+
// the error as is.
76+
if subcommandName != "" && cmd.Command(subcommandName) != nil {
77+
return err
78+
}
79+
80+
// At this point either no args have been supplied or the (sub)command
81+
// (first arg) is not regognised.
82+
// We issue a warning and returun nil.
83+
return issueUnsupportedHookWarning(logger, cmd)
84+
}
85+
86+
// Define the supported hooks.
87+
base.Commands = []*cli.Command{
3488
ldcache.NewCommand(logger),
3589
symlinks.NewCommand(logger),
3690
chmod.NewCommand(logger),
3791
cudacompat.NewCommand(logger),
3892
disabledevicenodemodification.NewCommand(logger),
93+
{
94+
Name: "noop",
95+
Usage: "The noop hook performs no actions and is only added to facilitate basic testing of the CLI",
96+
Hidden: true,
97+
Action: func(_ context.Context, _ *cli.Command) error {
98+
return nil
99+
},
100+
},
39101
}
102+
103+
return base
40104
}
41105

42-
// IssueUnsupportedHookWarning logs a warning that no hook or an unsupported
106+
// issueUnsupportedHookWarning logs a warning that no hook or an unsupported
43107
// hook has been specified.
44108
// This happens if a subcommand is provided that does not match one of the
45109
// subcommands that has been explicitly specified.
46-
func IssueUnsupportedHookWarning(logger logger.Interface, c *cli.Command) {
110+
func issueUnsupportedHookWarning(logger logger.Interface, c *cli.Command) error {
47111
args := c.Args().Slice()
48112
if len(args) == 0 {
49113
logger.Warningf("No CDI hook specified")
50114
} else {
51115
logger.Warningf("Unsupported CDI hook: %v", args[0])
52116
}
117+
return nil
53118
}

cmd/nvidia-cdi-hook/main.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func main() {
4545
opts := options{}
4646

4747
// Create the top-level CLI
48-
c := cli.Command{
48+
c := commands.ConfigureCDIHookCommand(logger, &cli.Command{
4949
Name: "NVIDIA CDI Hook",
5050
Usage: "Command to structure files for usage inside a container, called as hooks from a container runtime, defined in a CDI yaml file",
5151
Version: info.GetVersionString(),
@@ -61,19 +61,6 @@ func main() {
6161
logger.SetLevel(logLevel)
6262
return ctx, nil
6363
},
64-
// We set the default action for the `nvidia-cdi-hook` command to issue a
65-
// warning and exit with no error.
66-
// This means that if an unsupported hook is run, a container will not fail
67-
// to launch. An unsupported hook could be the result of a CDI specification
68-
// referring to a new hook that is not yet supported by an older NVIDIA
69-
// Container Toolkit version or a hook that has been removed in newer
70-
// version.
71-
Action: func(ctx context.Context, cmd *cli.Command) error {
72-
commands.IssueUnsupportedHookWarning(logger, cmd)
73-
return nil
74-
},
75-
// Define the subcommands
76-
Commands: commands.New(logger),
7764
Flags: []cli.Flag{
7865
&cli.BoolFlag{
7966
Name: "debug",
@@ -91,7 +78,7 @@ func main() {
9178
Sources: cli.EnvVars("NVIDIA_CTK_QUIET", "NVIDIA_CDI_QUIET"),
9279
},
9380
},
94-
}
81+
})
9582

9683
// Run the CLI
9784
err := c.Run(context.Background(), os.Args)

cmd/nvidia-ctk/hook/hook.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
package hook
1818

1919
import (
20-
"context"
21-
2220
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/commands"
2321
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
2422

@@ -39,23 +37,8 @@ func NewCommand(logger logger.Interface) *cli.Command {
3937

4038
// build
4139
func (m hookCommand) build() *cli.Command {
42-
// Create the 'hook' subcommand
43-
hook := cli.Command{
40+
return commands.ConfigureCDIHookCommand(m.logger, &cli.Command{
4441
Name: "hook",
4542
Usage: "A collection of hooks that may be injected into an OCI spec",
46-
// We set the default action for the `hook` subcommand to issue a
47-
// warning and exit with no error.
48-
// This means that if an unsupported hook is run, a container will not fail
49-
// to launch. An unsupported hook could be the result of a CDI specification
50-
// referring to a new hook that is not yet supported by an older NVIDIA
51-
// Container Toolkit version or a hook that has been removed in newer
52-
// version.
53-
Action: func(ctx context.Context, cmd *cli.Command) error {
54-
commands.IssueUnsupportedHookWarning(m.logger, cmd)
55-
return nil
56-
},
57-
Commands: commands.New(m.logger),
58-
}
59-
60-
return &hook
43+
})
6144
}

0 commit comments

Comments
 (0)