mirror of
				https://github.com/NVIDIA/nvidia-container-toolkit
				synced 2025-06-26 18:18:24 +00:00 
			
		
		
		
	Extend nvidia-ctk config command to allow options to be set
Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
		
							parent
							
								
									149a8d7bd8
								
							
						
					
					
						commit
						4addb292b1
					
				| @ -4,9 +4,9 @@ | ||||
| * Added support for generating OCI hook JSON file to `nvidia-ctk runtime configure` command. | ||||
| * Remove installation of OCI hook JSON from RPM package. | ||||
| * Refactored config for `nvidia-container-runtime-hook`. | ||||
| * Added a `nvidia-ctk config` command which supports setting config options using a `--set` flag. | ||||
| 
 | ||||
| ## v1.14.0-rc.2 | ||||
| 
 | ||||
| * Fix bug causing incorrect nvidia-smi symlink to be created on WSL2 systems with multiple driver roots. | ||||
| * Remove dependency on coreutils when installing package on RPM-based systems. | ||||
| * Create ouput folders if required when running `nvidia-ctk runtime configure` | ||||
|  | ||||
| @ -16,6 +16,31 @@ nvidia-ctk runtime configure --set-as-default | ||||
| will ensure that the NVIDIA Container Runtime is added as the default runtime to the default container | ||||
| engine. | ||||
| 
 | ||||
| ## Configure the NVIDIA Container Toolkit | ||||
| 
 | ||||
| The `config` command of the `nvidia-ctk` CLI allows a user to display and manipulate the NVIDIA Container Toolkit | ||||
| configuration. | ||||
| 
 | ||||
| For example, running the following command: | ||||
| ```bash | ||||
| nvidia-ctk config default | ||||
| ``` | ||||
| will display the default config for the detected platform. | ||||
| 
 | ||||
| Whereas | ||||
| ```bash | ||||
| nvidia-ctk config | ||||
| ``` | ||||
| will display the effective NVIDIA Container Toolkit config using the configured config file, and running: | ||||
| 
 | ||||
| Individual config options can be set by specifying these are key-value pairs to the `--set` argument: | ||||
| 
 | ||||
| ```bash | ||||
| nvidia-ctk config --set nvidia-container-cli.no-cgroups=true | ||||
| ``` | ||||
| 
 | ||||
| By default, all commands output to `STDOUT`, but specifying the `--output` flag writes the config to the specified file. | ||||
| 
 | ||||
| ### Generate CDI specifications | ||||
| 
 | ||||
| The [Container Device Interface (CDI)](https://github.com/container-orchestrated-devices/container-device-interface) provides | ||||
|  | ||||
| @ -17,7 +17,15 @@ | ||||
| package config | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	createdefault "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/create-default" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/flags" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/logger" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| @ -26,6 +34,12 @@ type command struct { | ||||
| 	logger logger.Interface | ||||
| } | ||||
| 
 | ||||
| // options stores the subcommand options
 | ||||
| type options struct { | ||||
| 	flags.Options | ||||
| 	sets cli.StringSlice | ||||
| } | ||||
| 
 | ||||
| // NewCommand constructs an config command with the specified logger
 | ||||
| func NewCommand(logger logger.Interface) *cli.Command { | ||||
| 	c := command{ | ||||
| @ -36,10 +50,42 @@ func NewCommand(logger logger.Interface) *cli.Command { | ||||
| 
 | ||||
| // build
 | ||||
| func (m command) build() *cli.Command { | ||||
| 	opts := options{} | ||||
| 
 | ||||
| 	// Create the 'config' command
 | ||||
| 	c := cli.Command{ | ||||
| 		Name:  "config", | ||||
| 		Usage: "Interact with the NVIDIA Container Toolkit configuration", | ||||
| 		Action: func(ctx *cli.Context) error { | ||||
| 			return run(ctx, &opts) | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	c.Flags = []cli.Flag{ | ||||
| 		&cli.StringFlag{ | ||||
| 			Name:        "config-file", | ||||
| 			Aliases:     []string{"config", "c"}, | ||||
| 			Usage:       "Specify the config file to modify.", | ||||
| 			Value:       config.GetConfigFilePath(), | ||||
| 			Destination: &opts.Config, | ||||
| 		}, | ||||
| 		&cli.StringSliceFlag{ | ||||
| 			Name:        "set", | ||||
| 			Usage:       "Set a config value using the pattern key=value. If value is empty, this is equivalent to specifying the same key in unset. This flag can be specified multiple times", | ||||
| 			Destination: &opts.sets, | ||||
| 		}, | ||||
| 		&cli.BoolFlag{ | ||||
| 			Name:        "in-place", | ||||
| 			Aliases:     []string{"i"}, | ||||
| 			Usage:       "Modify the config file in-place", | ||||
| 			Destination: &opts.InPlace, | ||||
| 		}, | ||||
| 		&cli.StringFlag{ | ||||
| 			Name:        "output", | ||||
| 			Aliases:     []string{"o"}, | ||||
| 			Usage:       "Specify the output file to write to; If not specified, the output is written to stdout", | ||||
| 			Destination: &opts.Output, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	c.Subcommands = []*cli.Command{ | ||||
| @ -48,3 +94,71 @@ func (m command) build() *cli.Command { | ||||
| 
 | ||||
| 	return &c | ||||
| } | ||||
| 
 | ||||
| func run(c *cli.Context, opts *options) error { | ||||
| 	cfgToml, err := config.New( | ||||
| 		config.WithConfigFile(opts.Config), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to create config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	for _, set := range opts.sets.Value() { | ||||
| 		key, value, err := (*configToml)(cfgToml).setFlagToKeyValue(set) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("invalid --set option %v: %w", set, err) | ||||
| 		} | ||||
| 		cfgToml.Set(key, value) | ||||
| 	} | ||||
| 
 | ||||
| 	cfgToml.Save(os.Stdout) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type configToml config.Toml | ||||
| 
 | ||||
| var errInvalidConfigOption = errors.New("invalid config option") | ||||
| var errInvalidFormat = errors.New("invalid format") | ||||
| 
 | ||||
| // setFlagToKeyValue converts a --set flag to a key-value pair.
 | ||||
| // The set flag is of the form key[=value], with the value being optional if key refers to a
 | ||||
| // boolean config option.
 | ||||
| func (c *configToml) setFlagToKeyValue(setFlag string) (string, interface{}, error) { | ||||
| 	if c == nil { | ||||
| 		return "", nil, errInvalidConfigOption | ||||
| 	} | ||||
| 
 | ||||
| 	setParts := strings.SplitN(setFlag, "=", 2) | ||||
| 	key := setParts[0] | ||||
| 
 | ||||
| 	v := (*config.Toml)(c).Get(key) | ||||
| 	if v == nil { | ||||
| 		return key, nil, errInvalidConfigOption | ||||
| 	} | ||||
| 	switch v.(type) { | ||||
| 	case bool: | ||||
| 		if len(setParts) == 1 { | ||||
| 			return key, true, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(setParts) != 2 { | ||||
| 		return key, nil, fmt.Errorf("%w: expected key=value; got %v", errInvalidFormat, setFlag) | ||||
| 	} | ||||
| 
 | ||||
| 	value := setParts[1] | ||||
| 	switch vt := v.(type) { | ||||
| 	case bool: | ||||
| 		b, err := strconv.ParseBool(value) | ||||
| 		if err != nil { | ||||
| 			return key, value, fmt.Errorf("%w: %w", errInvalidFormat, err) | ||||
| 		} | ||||
| 		return key, b, err | ||||
| 	case string: | ||||
| 		return key, value, nil | ||||
| 	case []string: | ||||
| 		return key, strings.Split(value, ","), nil | ||||
| 	default: | ||||
| 		return key, nil, fmt.Errorf("unsupported type for %v (%v)", setParts, vt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										173
									
								
								cmd/nvidia-ctk/config/config_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								cmd/nvidia-ctk/config/config_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | ||||
| /** | ||||
| # Copyright (c) NVIDIA CORPORATION.  All rights reserved. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| **/ | ||||
| 
 | ||||
| package config | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config" | ||||
| 	"github.com/pelletier/go-toml" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
| 
 | ||||
| func TestSetFlagToKeyValue(t *testing.T) { | ||||
| 	testCases := []struct { | ||||
| 		description   string | ||||
| 		config        map[string]interface{} | ||||
| 		setFlag       string | ||||
| 		expectedKey   string | ||||
| 		expectedValue interface{} | ||||
| 		expectedError error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			description:   "empty config returns an error", | ||||
| 			setFlag:       "anykey=value", | ||||
| 			expectedKey:   "anykey", | ||||
| 			expectedError: errInvalidConfigOption, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "option not present returns an error", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"defined": "defined-value", | ||||
| 			}, | ||||
| 			setFlag:       "undefined=new-value", | ||||
| 			expectedKey:   "undefined", | ||||
| 			expectedError: errInvalidConfigOption, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "boolean option assumes true", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"boolean": false, | ||||
| 			}, | ||||
| 			setFlag:       "boolean", | ||||
| 			expectedKey:   "boolean", | ||||
| 			expectedValue: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "boolean option returns true", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"boolean": false, | ||||
| 			}, | ||||
| 			setFlag:       "boolean=true", | ||||
| 			expectedKey:   "boolean", | ||||
| 			expectedValue: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "boolean option returns false", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"boolean": false, | ||||
| 			}, | ||||
| 			setFlag:       "boolean=false", | ||||
| 			expectedKey:   "boolean", | ||||
| 			expectedValue: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "invalid boolean option returns error", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"boolean": false, | ||||
| 			}, | ||||
| 			setFlag:       "boolean=something", | ||||
| 			expectedKey:   "boolean", | ||||
| 			expectedValue: "something", | ||||
| 			expectedError: errInvalidFormat, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "string option requires value", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": "value", | ||||
| 			}, | ||||
| 			setFlag:       "string", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: nil, | ||||
| 			expectedError: errInvalidFormat, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "string option returns value", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": "value", | ||||
| 			}, | ||||
| 			setFlag:       "string=string-value", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: "string-value", | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "string option returns value with equals", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": "value", | ||||
| 			}, | ||||
| 			setFlag:       "string=string-value=more", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: "string-value=more", | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "string option treats bool value as string", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": "value", | ||||
| 			}, | ||||
| 			setFlag:       "string=true", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: "true", | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "string option treats int value as string", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": "value", | ||||
| 			}, | ||||
| 			setFlag:       "string=5", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: "5", | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "[]string option returns single value", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": []string{"value"}, | ||||
| 			}, | ||||
| 			setFlag:       "string=string-value", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: []string{"string-value"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "[]string option returns multiple values", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": []string{"value"}, | ||||
| 			}, | ||||
| 			setFlag:       "string=first,second", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: []string{"first", "second"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			description: "[]string option returns values with equals", | ||||
| 			config: map[string]interface{}{ | ||||
| 				"string": []string{"value"}, | ||||
| 			}, | ||||
| 			setFlag:       "string=first=1,second=2", | ||||
| 			expectedKey:   "string", | ||||
| 			expectedValue: []string{"first=1", "second=2"}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.description, func(t *testing.T) { | ||||
| 			tree, _ := toml.TreeFromMap(tc.config) | ||||
| 			cfgToml := (*config.Toml)(tree) | ||||
| 			k, v, err := (*configToml)(cfgToml).setFlagToKeyValue(tc.setFlag) | ||||
| 			require.ErrorIs(t, err, tc.expectedError) | ||||
| 			require.EqualValues(t, tc.expectedKey, k) | ||||
| 			require.EqualValues(t, tc.expectedValue, v) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| @ -18,10 +18,8 @@ package defaultsubcommand | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 
 | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/flags" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/logger" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| @ -31,11 +29,6 @@ type command struct { | ||||
| 	logger logger.Interface | ||||
| } | ||||
| 
 | ||||
| // options stores the subcommand options
 | ||||
| type options struct { | ||||
| 	output string | ||||
| } | ||||
| 
 | ||||
| // NewCommand constructs a default command with the specified logger
 | ||||
| func NewCommand(logger logger.Interface) *cli.Command { | ||||
| 	c := command{ | ||||
| @ -46,7 +39,7 @@ func NewCommand(logger logger.Interface) *cli.Command { | ||||
| 
 | ||||
| // build creates the CLI command
 | ||||
| func (m command) build() *cli.Command { | ||||
| 	opts := options{} | ||||
| 	opts := flags.Options{} | ||||
| 
 | ||||
| 	// Create the 'default' command
 | ||||
| 	c := cli.Command{ | ||||
| @ -66,24 +59,24 @@ func (m command) build() *cli.Command { | ||||
| 			Name:        "output", | ||||
| 			Aliases:     []string{"o"}, | ||||
| 			Usage:       "Specify the output file to write to; If not specified, the output is written to stdout", | ||||
| 			Destination: &opts.output, | ||||
| 			Destination: &opts.Output, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	return &c | ||||
| } | ||||
| 
 | ||||
| func (m command) validateFlags(c *cli.Context, opts *options) error { | ||||
| 	return nil | ||||
| func (m command) validateFlags(c *cli.Context, opts *flags.Options) error { | ||||
| 	return opts.Validate() | ||||
| } | ||||
| 
 | ||||
| func (m command) run(c *cli.Context, opts *options) error { | ||||
| func (m command) run(c *cli.Context, opts *flags.Options) error { | ||||
| 	cfgToml, err := config.New() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to load or create config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err := opts.ensureOutputFolder(); err != nil { | ||||
| 	if err := opts.EnsureOutputFolder(); err != nil { | ||||
| 		return fmt.Errorf("failed to create output directory: %v", err) | ||||
| 	} | ||||
| 	output, err := opts.CreateOutput() | ||||
| @ -99,31 +92,3 @@ func (m command) run(c *cli.Context, opts *options) error { | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ensureOutputFolder creates the output folder if it does not exist.
 | ||||
| // If the output folder is not specified (i.e. output to STDOUT), it is ignored.
 | ||||
| func (o options) ensureOutputFolder() error { | ||||
| 	if o.output == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if dir := filepath.Dir(o.output); dir != "" { | ||||
| 		return os.MkdirAll(dir, 0755) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o options) CreateOutput() (io.WriteCloser, error) { | ||||
| 	if o.output != "" { | ||||
| 		return os.Create(o.output) | ||||
| 	} | ||||
| 
 | ||||
| 	return nullCloser{os.Stdout}, nil | ||||
| } | ||||
| 
 | ||||
| type nullCloser struct { | ||||
| 	io.Writer | ||||
| } | ||||
| 
 | ||||
| func (d nullCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
							
								
								
									
										71
									
								
								cmd/nvidia-ctk/config/flags/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								cmd/nvidia-ctk/config/flags/options.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| /** | ||||
| # Copyright (c) NVIDIA CORPORATION.  All rights reserved. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| **/ | ||||
| 
 | ||||
| package flags | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| ) | ||||
| 
 | ||||
| // Options stores options for the config commands
 | ||||
| type Options struct { | ||||
| 	Config  string | ||||
| 	Output  string | ||||
| 	InPlace bool | ||||
| } | ||||
| 
 | ||||
| // Validate checks whether the options are valid.
 | ||||
| func (o Options) Validate() error { | ||||
| 	if o.InPlace && o.Output != "" { | ||||
| 		return fmt.Errorf("cannot specify both --in-place and --output") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // EnsureOutputFolder creates the output folder if it does not exist.
 | ||||
| // If the output folder is not specified (i.e. output to STDOUT), it is ignored.
 | ||||
| func (o Options) EnsureOutputFolder() error { | ||||
| 	if o.Output == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if dir := filepath.Dir(o.Output); dir != "" { | ||||
| 		return os.MkdirAll(dir, 0755) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // CreateOutput creates the writer for the output.
 | ||||
| func (o Options) CreateOutput() (io.WriteCloser, error) { | ||||
| 	if o.Output != "" { | ||||
| 		return os.Create(o.Output) | ||||
| 	} | ||||
| 
 | ||||
| 	return nullCloser{os.Stdout}, nil | ||||
| } | ||||
| 
 | ||||
| // nullCloser is a writer that does nothing on Close.
 | ||||
| type nullCloser struct { | ||||
| 	io.Writer | ||||
| } | ||||
| 
 | ||||
| // Close is a no-op for a nullCloser.
 | ||||
| func (d nullCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
| @ -148,6 +148,21 @@ func (t Toml) format(contents []byte) ([]byte, error) { | ||||
| 	return replaced, nil | ||||
| } | ||||
| 
 | ||||
| // Delete deletes the specified key from the TOML config.
 | ||||
| func (t *Toml) Delete(key string) error { | ||||
| 	return (*toml.Tree)(t).Delete(key) | ||||
| } | ||||
| 
 | ||||
| // Get returns the value for the specified key.
 | ||||
| func (t *Toml) Get(key string) interface{} { | ||||
| 	return (*toml.Tree)(t).Get(key) | ||||
| } | ||||
| 
 | ||||
| // Set sets the specified key to the specified value in the TOML config.
 | ||||
| func (t *Toml) Set(key string, value interface{}) { | ||||
| 	(*toml.Tree)(t).Set(key, value) | ||||
| } | ||||
| 
 | ||||
| // commentDefaults applies the required comments for default values to the Toml.
 | ||||
| func (t *Toml) commentDefaults() *Toml { | ||||
| 	asToml := (*toml.Tree)(t) | ||||
|  | ||||
| @ -4,7 +4,7 @@ set -e | ||||
| 
 | ||||
| case "$1" in | ||||
|     configure) | ||||
|         /usr/bin/nvidia-ctk --quiet config default --in-place --config=/etc/nvidia-container-runtime/config.toml | ||||
|         /usr/bin/nvidia-ctk --quiet config --config-file=/etc/nvidia-container-runtime/config.toml --in-place | ||||
|     ;; | ||||
| 
 | ||||
|     abort-upgrade|abort-remove|abort-deconfigure) | ||||
|  | ||||
| @ -59,7 +59,7 @@ rm -rf %{_localstatedir}/lib/rpm-state/nvidia-container-toolkit | ||||
| ln -sf %{_bindir}/nvidia-container-runtime-hook %{_bindir}/nvidia-container-toolkit | ||||
| 
 | ||||
| # Generate the default config; If this file already exists no changes are made. | ||||
| %{_bindir}/nvidia-ctk --quiet config default --in-place --config=%{_sysconfdir}/nvidia-container-runtime/config.toml | ||||
| %{_bindir}/nvidia-ctk --quiet config --config-file=%{_sysconfdir}/nvidia-container-runtime/config.toml --in-place | ||||
| 
 | ||||
| %postun | ||||
| if [ "$1" = 0 ]; then  # package is uninstalled, not upgraded | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user