Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 71 additions & 6 deletions cmd/nvidia-cdi-hook/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package commands

import (
"context"
"strings"

"github.com/urfave/cli/v3"

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

// New creates the commands associated with supported CDI hooks.
// These are shared by the nvidia-cdi-hook and nvidia-ctk hook commands.
func New(logger logger.Interface) []*cli.Command {
return []*cli.Command{
// ConfigureCDIHookCommand configures a base command with supported CDI hooks
// and error handling for unsupported hooks.
// This allows the same command to be used for the nvidia-cdi-hook and
// nvidia-ctk hook commands.
func ConfigureCDIHookCommand(logger logger.Interface, base *cli.Command) *cli.Command {
// We set the default action for the command to issue a warning and exit
// with no error.
// This means that if an unsupported hook is run, a container will not fail
// to launch. An unsupported hook could be the result of a CDI specification
// referring to a new hook that is not yet supported by an older NVIDIA
// Container Toolkit version or a hook that has been removed in newer
// version.
base.Action = func(ctx context.Context, cmd *cli.Command) error {
return issueUnsupportedHookWarning(logger, cmd)
}
// CommandNotFound is triggered when an unrecognised (sub)command is detected.
// We assume that an unrecognised (sub)command represents an unsupported hook
// (usually a hook that was added or removed)
base.CommandNotFound = func(ctx context.Context, cmd *cli.Command, commandName string) {
_ = issueUnsupportedHookWarning(logger, cmd)
}
// OnUsageError is triggered when an unexpected flag is detected.
// We check the invoked command to determine whether it is an expected
// hook, and assume that this is an unsupported hook otherwise.
base.OnUsageError = func(ctx context.Context, cmd *cli.Command, err error, isSubcommand bool) error {
// If this is not an error that comes from parsing an unrecognised flag,
// return it as is.
if !strings.HasPrefix(err.Error(), "flag provided but not defined: -") {
return err
}

// If the first argument is a recognised command, we return the error as
// is since it represents an incorrect argument to the specific hook.
var subcommandName string
for _, arg := range cmd.Args().Slice() {
if strings.HasPrefix(arg, "-") {
continue
}
subcommandName = arg
break
}
// If a subcommand is detected and is a recognised subcommand, we return
// the error as is.
if subcommandName != "" && cmd.Command(subcommandName) != nil {
return err
}

// At this point either no args have been supplied or the (sub)command
// (first arg) is not regognised.
// We issue a warning and returun nil.
return issueUnsupportedHookWarning(logger, cmd)
}

// Define the supported hooks.
base.Commands = []*cli.Command{
ldcache.NewCommand(logger),
symlinks.NewCommand(logger),
chmod.NewCommand(logger),
cudacompat.NewCommand(logger),
disabledevicenodemodification.NewCommand(logger),
{
Name: "noop",
Usage: "The noop hook performs no actions and is only added to facilitate basic testing of the CLI",
Hidden: true,
Action: func(_ context.Context, _ *cli.Command) error {
return nil
},
},
}

return base
}

// IssueUnsupportedHookWarning logs a warning that no hook or an unsupported
// issueUnsupportedHookWarning logs a warning that no hook or an unsupported
// hook has been specified.
// This happens if a subcommand is provided that does not match one of the
// subcommands that has been explicitly specified.
func IssueUnsupportedHookWarning(logger logger.Interface, c *cli.Command) {
func issueUnsupportedHookWarning(logger logger.Interface, c *cli.Command) error {
args := c.Args().Slice()
if len(args) == 0 {
logger.Warningf("No CDI hook specified")
} else {
logger.Warningf("Unsupported CDI hook: %v", args[0])
}
return nil
}
17 changes: 2 additions & 15 deletions cmd/nvidia-cdi-hook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func main() {
opts := options{}

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

// Run the CLI
err := c.Run(context.Background(), os.Args)
Expand Down
21 changes: 2 additions & 19 deletions cmd/nvidia-ctk/hook/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package hook

import (
"context"

"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/commands"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"

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

// build
func (m hookCommand) build() *cli.Command {
// Create the 'hook' subcommand
hook := cli.Command{
return commands.ConfigureCDIHookCommand(m.logger, &cli.Command{
Name: "hook",
Usage: "A collection of hooks that may be injected into an OCI spec",
// We set the default action for the `hook` subcommand to issue a
// warning and exit with no error.
// This means that if an unsupported hook is run, a container will not fail
// to launch. An unsupported hook could be the result of a CDI specification
// referring to a new hook that is not yet supported by an older NVIDIA
// Container Toolkit version or a hook that has been removed in newer
// version.
Action: func(ctx context.Context, cmd *cli.Command) error {
commands.IssueUnsupportedHookWarning(m.logger, cmd)
return nil
},
Commands: commands.New(m.logger),
}

return &hook
})
}
Loading