diff --git a/cmd/nvidia-ctk-installer/container/runtime/runtime.go b/cmd/nvidia-ctk-installer/container/runtime/runtime.go index 950e1aeca..132bf6956 100644 --- a/cmd/nvidia-ctk-installer/container/runtime/runtime.go +++ b/cmd/nvidia-ctk-installer/container/runtime/runtime.go @@ -138,6 +138,18 @@ func Flags(opts *Options) []cli.Flag { // Validate checks whether the specified options are valid func (opts *Options) Validate(logger logger.Interface, c *cli.Command, runtime string, toolkitRoot string, to *toolkit.Options) error { + // Check that the specified runtime is supported. + switch runtime { + case containerd.Name: + case crio.Name: + case docker.Name: + case string(None): + // If the none runtime is selected, we bypass any additional validations. + return nil + default: + return fmt.Errorf("invalid runtime %q; expected one of [containerd | crio | docker | none]", runtime) + } + // We set this option here to ensure that it is available in future calls. opts.RuntimeDir = toolkitRoot @@ -212,33 +224,42 @@ func (opts *Options) Validate(logger logger.Interface, c *cli.Command, runtime s return nil } -func Setup(c *cli.Command, opts *Options, runtime string) error { - switch runtime { +type Runtime string + +// A None runtime is used to disable runtime configuration. +const None Runtime = "none" + +func (r Runtime) Setup(c *cli.Command, opts *Options) error { + switch string(r) { case containerd.Name: return containerd.Setup(c, &opts.Options, &opts.containerdOptions) case crio.Name: return crio.Setup(c, &opts.Options, &opts.crioOptions) case docker.Name: return docker.Setup(c, &opts.Options) + case string(None): + return nil default: - return fmt.Errorf("undefined runtime %v", runtime) + return fmt.Errorf("undefined runtime %v", r) } } -func Cleanup(c *cli.Command, opts *Options, runtime string) error { - switch runtime { +func (r Runtime) Cleanup(c *cli.Command, opts *Options, runtime string) error { + switch string(r) { case containerd.Name: return containerd.Cleanup(c, &opts.Options, &opts.containerdOptions) case crio.Name: return crio.Cleanup(c, &opts.Options, &opts.crioOptions) case docker.Name: return docker.Cleanup(c, &opts.Options) + case string(None): + return nil default: return fmt.Errorf("undefined runtime %v", runtime) } } -func GetLowlevelRuntimePaths(opts *Options, runtime string) ([]string, error) { +func (r Runtime) GetLowlevelRuntimePaths(opts *Options, runtime string) ([]string, error) { switch runtime { case containerd.Name: return containerd.GetLowlevelRuntimePaths(&opts.Options, &opts.containerdOptions) @@ -246,6 +267,8 @@ func GetLowlevelRuntimePaths(opts *Options, runtime string) ([]string, error) { return crio.GetLowlevelRuntimePaths(&opts.Options) case docker.Name: return docker.GetLowlevelRuntimePaths(&opts.Options) + case string(None): + return nil, nil default: return nil, fmt.Errorf("undefined runtime %v", runtime) } diff --git a/cmd/nvidia-ctk-installer/main.go b/cmd/nvidia-ctk-installer/main.go index 2500ee273..66d666b5e 100644 --- a/cmd/nvidia-ctk-installer/main.go +++ b/cmd/nvidia-ctk-installer/main.go @@ -28,7 +28,6 @@ const ( defaultRuntime = "docker" ) -var availableRuntimes = map[string]struct{}{"docker": {}, "crio": {}, "containerd": {}} var defaultLowLevelRuntimes = []string{"runc", "crun"} var waitingForSignal = make(chan bool, 1) @@ -175,9 +174,6 @@ func (a *app) validateFlags(c *cli.Command, o *options) error { if o.toolkitInstallDir == "" { return fmt.Errorf("the install root must be specified") } - if _, exists := availableRuntimes[o.runtime]; !exists { - return fmt.Errorf("unknown runtime: %v", o.runtime) - } if filepath.Base(o.pidFile) != toolkitPidFilename { return fmt.Errorf("invalid toolkit.pid path %v", o.pidFile) } @@ -185,9 +181,11 @@ func (a *app) validateFlags(c *cli.Command, o *options) error { if err := a.toolkit.ValidateOptions(&o.toolkitOptions); err != nil { return err } + if err := o.runtimeOptions.Validate(a.logger, c, o.runtime, o.toolkitRoot(), &o.toolkitOptions); err != nil { return err } + return nil } @@ -201,6 +199,8 @@ func (a *app) Run(c *cli.Command, o *options) error { } defer a.shutdown(o.pidFile) + runtime := runtime.Runtime(o.runtime) + if len(o.toolkitOptions.ContainerRuntimeRuntimes) == 0 { lowlevelRuntimePaths, err := runtime.GetLowlevelRuntimePaths(&o.runtimeOptions, o.runtime) if err != nil { @@ -216,21 +216,22 @@ func (a *app) Run(c *cli.Command, o *options) error { return fmt.Errorf("unable to install toolkit: %v", err) } - err = runtime.Setup(c, &o.runtimeOptions, o.runtime) + err = runtime.Setup(c, &o.runtimeOptions) if err != nil { return fmt.Errorf("unable to setup runtime: %v", err) } + if o.noDaemon { + return nil + } - if !o.noDaemon { - err = a.waitForSignal() - if err != nil { - return fmt.Errorf("unable to wait for signal: %v", err) - } + err = a.waitForSignal() + if err != nil { + return fmt.Errorf("unable to wait for signal: %v", err) + } - err = runtime.Cleanup(c, &o.runtimeOptions, o.runtime) - if err != nil { - return fmt.Errorf("unable to cleanup runtime: %v", err) - } + err = runtime.Cleanup(c, &o.runtimeOptions, o.runtime) + if err != nil { + return fmt.Errorf("unable to cleanup runtime: %v", err) } return nil