mirror of
				https://github.com/NVIDIA/nvidia-container-toolkit
				synced 2025-06-26 18:18:24 +00:00 
			
		
		
		
	Migrate docker config to engine.Interface
Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
		
							parent
							
								
									e5bb4d2718
								
							
						
					
					
						commit
						9fff19da23
					
				| @ -127,13 +127,14 @@ func (m command) configureDocker(c *cli.Context, config *config) error { | |||||||
| 		configFilePath = defaultDockerConfigFilePath | 		configFilePath = defaultDockerConfigFilePath | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cfg, err := docker.LoadConfig(configFilePath) | 	cfg, err := docker.New( | ||||||
|  | 		docker.WithPath(configFilePath), | ||||||
|  | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to load config: %v", err) | 		return fmt.Errorf("unable to load config: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = docker.UpdateConfig( | 	err = cfg.AddRuntime( | ||||||
| 		cfg, |  | ||||||
| 		config.nvidiaOptions.RuntimeName, | 		config.nvidiaOptions.RuntimeName, | ||||||
| 		config.nvidiaOptions.RuntimePath, | 		config.nvidiaOptions.RuntimePath, | ||||||
| 		config.nvidiaOptions.SetAsDefault, | 		config.nvidiaOptions.SetAsDefault, | ||||||
| @ -150,12 +151,16 @@ func (m command) configureDocker(c *cli.Context, config *config) error { | |||||||
| 		os.Stdout.WriteString(fmt.Sprintf("%s\n", output)) | 		os.Stdout.WriteString(fmt.Sprintf("%s\n", output)) | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	err = docker.FlushConfig(cfg, configFilePath) | 	n, err := cfg.Save(configFilePath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to flush config: %v", err) | 		return fmt.Errorf("unable to flush config: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	m.logger.Infof("Wrote updated config to %v", configFilePath) | 	if n == 0 { | ||||||
|  | 		m.logger.Infof("Removed empty config from %v", configFilePath) | ||||||
|  | 	} else { | ||||||
|  | 		m.logger.Infof("Wrote updated config to %v", configFilePath) | ||||||
|  | 	} | ||||||
| 	m.logger.Infof("It is recommended that the docker daemon be restarted.") | 	m.logger.Infof("It is recommended that the docker daemon be restarted.") | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | |||||||
| @ -17,47 +17,39 @@ | |||||||
| package docker | package docker | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/ioutil" |  | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
| 	log "github.com/sirupsen/logrus" | 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // LoadConfig loads the docker config from disk
 | const ( | ||||||
| func LoadConfig(configFilePath string) (map[string]interface{}, error) { | 	defaultDockerRuntime = "runc" | ||||||
| 	log.Infof("Loading docker config from %v", configFilePath) | ) | ||||||
| 
 | 
 | ||||||
| 	info, err := os.Stat(configFilePath) | // Config defines a docker config file.
 | ||||||
| 	if os.IsExist(err) && info.IsDir() { | // TODO: This should not be public, but we need to access it from the tests in tools/container/docker
 | ||||||
| 		return nil, fmt.Errorf("config file is a directory") | type Config map[string]interface{} | ||||||
|  | 
 | ||||||
|  | // New creates a docker config with the specified options
 | ||||||
|  | func New(opts ...Option) (engine.Interface, error) { | ||||||
|  | 	b := &builder{} | ||||||
|  | 	for _, opt := range opts { | ||||||
|  | 		opt(b) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cfg := make(map[string]interface{}) | 	return b.build() | ||||||
| 
 |  | ||||||
| 	if os.IsNotExist(err) { |  | ||||||
| 		log.Infof("Config file does not exist, creating new one") |  | ||||||
| 		return cfg, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	readBytes, err := ioutil.ReadFile(configFilePath) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("unable to read config: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	reader := bytes.NewReader(readBytes) |  | ||||||
| 	if err := json.NewDecoder(reader).Decode(&cfg); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	log.Infof("Successfully loaded config") |  | ||||||
| 	return cfg, nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // UpdateConfig updates the docker config to include the nvidia runtimes
 | // AddRuntime adds a new runtime to the docker config
 | ||||||
| func UpdateConfig(config map[string]interface{}, runtimeName string, runtimePath string, setAsDefault bool) error { | func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error { | ||||||
|  | 	if c == nil { | ||||||
|  | 		return fmt.Errorf("config is nil") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	config := *c | ||||||
|  | 
 | ||||||
| 	// Read the existing runtimes
 | 	// Read the existing runtimes
 | ||||||
| 	runtimes := make(map[string]interface{}) | 	runtimes := make(map[string]interface{}) | ||||||
| 	if _, exists := config["runtimes"]; exists { | 	if _, exists := config["runtimes"]; exists { | ||||||
| @ -65,53 +57,84 @@ func UpdateConfig(config map[string]interface{}, runtimeName string, runtimePath | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Add / update the runtime definitions
 | 	// Add / update the runtime definitions
 | ||||||
| 	runtimes[runtimeName] = map[string]interface{}{ | 	runtimes[name] = map[string]interface{}{ | ||||||
| 		"path": runtimePath, | 		"path": path, | ||||||
| 		"args": []string{}, | 		"args": []string{}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Update the runtimes definition
 | 	config["runtimes"] = runtimes | ||||||
| 	if len(runtimes) > 0 { |  | ||||||
| 		config["runtimes"] = runtimes |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if setAsDefault { | 	if setAsDefault { | ||||||
| 		config["default-runtime"] = runtimeName | 		config["default-runtime"] = name | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	*c = config | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DefaultRuntime returns the default runtime for the docker config
 | ||||||
|  | func (c Config) DefaultRuntime() string { | ||||||
|  | 	r, ok := c["default-runtime"].(string) | ||||||
|  | 	if !ok { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RemoveRuntime removes a runtime from the docker config
 | ||||||
|  | func (c *Config) RemoveRuntime(name string) error { | ||||||
|  | 	if c == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	config := *c | ||||||
|  | 
 | ||||||
|  | 	if _, exists := config["default-runtime"]; exists { | ||||||
|  | 		defaultRuntime := config["default-runtime"].(string) | ||||||
|  | 		if defaultRuntime == name { | ||||||
|  | 			config["default-runtime"] = defaultDockerRuntime | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, exists := config["runtimes"]; exists { | ||||||
|  | 		runtimes := config["runtimes"].(map[string]interface{}) | ||||||
|  | 
 | ||||||
|  | 		delete(runtimes, name) | ||||||
|  | 
 | ||||||
|  | 		if len(runtimes) == 0 { | ||||||
|  | 			delete(config, "runtimes") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	*c = config | ||||||
|  | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FlushConfig flushes the updated/reverted config out to disk
 | // Save writes the config to the specified path
 | ||||||
| func FlushConfig(cfg map[string]interface{}, configFilePath string) error { | func (c Config) Save(path string) (int64, error) { | ||||||
| 	log.Infof("Flushing docker config to %v", configFilePath) | 	output, err := json.MarshalIndent(c, "", "    ") | ||||||
| 
 |  | ||||||
| 	output, err := json.MarshalIndent(cfg, "", "    ") |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to convert to JSON: %v", err) | 		return 0, fmt.Errorf("unable to convert to JSON: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch len(output) { | 	if len(output) == 0 { | ||||||
| 	case 0: | 		err := os.Remove(path) | ||||||
| 		err := os.Remove(configFilePath) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("unable to remove empty file: %v", err) | 			return 0, fmt.Errorf("unable to remove empty file: %v", err) | ||||||
| 		} |  | ||||||
| 		log.Infof("Config empty, removing file") |  | ||||||
| 	default: |  | ||||||
| 		f, err := os.Create(configFilePath) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return fmt.Errorf("unable to open %v for writing: %v", configFilePath, err) |  | ||||||
| 		} |  | ||||||
| 		defer f.Close() |  | ||||||
| 
 |  | ||||||
| 		_, err = f.WriteString(string(output)) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return fmt.Errorf("unable to write output: %v", err) |  | ||||||
| 		} | 		} | ||||||
|  | 		return 0, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	log.Infof("Successfully flushed config") | 	f, err := os.Create(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, fmt.Errorf("unable to open %v for writing: %v", path, err) | ||||||
|  | 	} | ||||||
|  | 	defer f.Close() | ||||||
| 
 | 
 | ||||||
| 	return nil | 	n, err := f.WriteString(string(output)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, fmt.Errorf("unable to write output: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return int64(n), nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| func TestUpdateConfigDefaultRuntime(t *testing.T) { | func TestUpdateConfigDefaultRuntime(t *testing.T) { | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| 		config                     map[string]interface{} | 		config                     Config | ||||||
| 		runtimeName                string | 		runtimeName                string | ||||||
| 		setAsDefault               bool | 		setAsDefault               bool | ||||||
| 		expectedDefaultRuntimeName interface{} | 		expectedDefaultRuntimeName interface{} | ||||||
| @ -63,7 +63,7 @@ func TestUpdateConfigDefaultRuntime(t *testing.T) { | |||||||
| 			if tc.config == nil { | 			if tc.config == nil { | ||||||
| 				tc.config = make(map[string]interface{}) | 				tc.config = make(map[string]interface{}) | ||||||
| 			} | 			} | ||||||
| 			err := UpdateConfig(tc.config, tc.runtimeName, "", tc.setAsDefault) | 			err := tc.config.AddRuntime(tc.runtimeName, "", tc.setAsDefault) | ||||||
| 			require.NoError(t, err) | 			require.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 			defaultRuntimeName := tc.config["default-runtime"] | 			defaultRuntimeName := tc.config["default-runtime"] | ||||||
| @ -74,7 +74,7 @@ func TestUpdateConfigDefaultRuntime(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| func TestUpdateConfigRuntimes(t *testing.T) { | func TestUpdateConfigRuntimes(t *testing.T) { | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| 		config         map[string]interface{} | 		config         Config | ||||||
| 		runtimes       map[string]string | 		runtimes       map[string]string | ||||||
| 		expectedConfig map[string]interface{} | 		expectedConfig map[string]interface{} | ||||||
| 	}{ | 	}{ | ||||||
| @ -198,7 +198,7 @@ func TestUpdateConfigRuntimes(t *testing.T) { | |||||||
| 	for i, tc := range testCases { | 	for i, tc := range testCases { | ||||||
| 		t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) { | 		t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) { | ||||||
| 			for runtimeName, runtimePath := range tc.runtimes { | 			for runtimeName, runtimePath := range tc.runtimes { | ||||||
| 				err := UpdateConfig(tc.config, runtimeName, runtimePath, false) | 				err := tc.config.AddRuntime(runtimeName, runtimePath, false) | ||||||
| 				require.NoError(t, err) | 				require.NoError(t, err) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										80
									
								
								internal/config/engine/docker/option.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								internal/config/engine/docker/option.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | /** | ||||||
|  | # 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 docker | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 
 | ||||||
|  | 	log "github.com/sirupsen/logrus" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type builder struct { | ||||||
|  | 	path string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Option defines a function that can be used to configure the config builder
 | ||||||
|  | type Option func(*builder) | ||||||
|  | 
 | ||||||
|  | // WithPath sets the path for the config builder
 | ||||||
|  | func WithPath(path string) Option { | ||||||
|  | 	return func(b *builder) { | ||||||
|  | 		b.path = path | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (b *builder) build() (*Config, error) { | ||||||
|  | 	if b.path == "" { | ||||||
|  | 		empty := make(Config) | ||||||
|  | 		return &empty, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return loadConfig(b.path) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // loadConfig loads the docker config from disk
 | ||||||
|  | func loadConfig(configFilePath string) (*Config, error) { | ||||||
|  | 	log.Infof("Loading docker config from %v", configFilePath) | ||||||
|  | 
 | ||||||
|  | 	info, err := os.Stat(configFilePath) | ||||||
|  | 	if os.IsExist(err) && info.IsDir() { | ||||||
|  | 		return nil, fmt.Errorf("config file is a directory") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cfg := make(Config) | ||||||
|  | 
 | ||||||
|  | 	if os.IsNotExist(err) { | ||||||
|  | 		log.Infof("Config file does not exist, creating new one") | ||||||
|  | 		return &cfg, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	readBytes, err := ioutil.ReadFile(configFilePath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("unable to read config: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	reader := bytes.NewReader(readBytes) | ||||||
|  | 	if err := json.NewDecoder(reader).Decode(&cfg); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Infof("Successfully loaded config") | ||||||
|  | 	return &cfg, nil | ||||||
|  | } | ||||||
| @ -20,11 +20,12 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" |  | ||||||
| 	"syscall" | 	"syscall" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine" | ||||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/docker" | 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/docker" | ||||||
|  | 	"github.com/NVIDIA/nvidia-container-toolkit/tools/container/operator" | ||||||
| 	log "github.com/sirupsen/logrus" | 	log "github.com/sirupsen/logrus" | ||||||
| 	cli "github.com/urfave/cli/v2" | 	cli "github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
| @ -170,7 +171,9 @@ func Setup(c *cli.Context, o *options) error { | |||||||
| 	} | 	} | ||||||
| 	o.runtimeDir = runtimeDir | 	o.runtimeDir = runtimeDir | ||||||
| 
 | 
 | ||||||
| 	cfg, err := LoadConfig(o.config) | 	cfg, err := docker.New( | ||||||
|  | 		docker.WithPath(o.config), | ||||||
|  | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to load config: %v", err) | 		return fmt.Errorf("unable to load config: %v", err) | ||||||
| 	} | 	} | ||||||
| @ -180,7 +183,8 @@ func Setup(c *cli.Context, o *options) error { | |||||||
| 		return fmt.Errorf("unable to update config: %v", err) | 		return fmt.Errorf("unable to update config: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = FlushConfig(cfg, o.config) | 	log.Infof("Flushing docker config to %v", o.config) | ||||||
|  | 	_, err = cfg.Save(o.config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to flush config: %v", err) | 		return fmt.Errorf("unable to flush config: %v", err) | ||||||
| 	} | 	} | ||||||
| @ -204,20 +208,26 @@ func Cleanup(c *cli.Context, o *options) error { | |||||||
| 		return fmt.Errorf("unable to parse args: %v", err) | 		return fmt.Errorf("unable to parse args: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cfg, err := LoadConfig(o.config) | 	cfg, err := docker.New( | ||||||
|  | 		docker.WithPath(o.config), | ||||||
|  | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to load config: %v", err) | 		return fmt.Errorf("unable to load config: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = RevertConfig(cfg) | 	err = RevertConfig(cfg, o) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to update config: %v", err) | 		return fmt.Errorf("unable to update config: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = FlushConfig(cfg, o.config) | 	log.Infof("Flushing docker config to %v", o.config) | ||||||
|  | 	n, err := cfg.Save(o.config) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("unable to flush config: %v", err) | 		return fmt.Errorf("unable to flush config: %v", err) | ||||||
| 	} | 	} | ||||||
|  | 	if n == 0 { | ||||||
|  | 		log.Infof("Config file is empty, removed") | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	err = RestartDocker(o) | 	err = RestartDocker(o) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -243,18 +253,17 @@ func ParseArgs(c *cli.Context) (string, error) { | |||||||
| 	return runtimeDir, nil | 	return runtimeDir, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LoadConfig loads the docker config from disk
 |  | ||||||
| func LoadConfig(config string) (map[string]interface{}, error) { |  | ||||||
| 	return docker.LoadConfig(config) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UpdateConfig updates the docker config to include the nvidia runtimes
 | // UpdateConfig updates the docker config to include the nvidia runtimes
 | ||||||
| func UpdateConfig(config map[string]interface{}, o *options) error { | func UpdateConfig(cfg engine.Interface, o *options) error { | ||||||
| 	for runtimeName, runtimePath := range o.getRuntimeBinaries() { | 	runtimes := operator.GetRuntimes( | ||||||
| 		setAsDefault := runtimeName == o.getDefaultRuntime() | 		operator.WithNvidiaRuntimeName(o.runtimeName), | ||||||
| 		err := docker.UpdateConfig(config, runtimeName, runtimePath, setAsDefault) | 		operator.WithSetAsDefault(o.setAsDefault), | ||||||
|  | 		operator.WithRoot(o.runtimeDir), | ||||||
|  | 	) | ||||||
|  | 	for name, runtime := range runtimes { | ||||||
|  | 		err := cfg.AddRuntime(name, runtime.Path, runtime.SetAsDefault) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("failed to update runtime %q: %v", runtimeName, err) | 			return fmt.Errorf("failed to update runtime %q: %v", name, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -262,33 +271,22 @@ func UpdateConfig(config map[string]interface{}, o *options) error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RevertConfig reverts the docker config to remove the nvidia runtime
 | // RevertConfig reverts the docker config to remove the nvidia runtime
 | ||||||
| func RevertConfig(config map[string]interface{}) error { | func RevertConfig(cfg engine.Interface, o *options) error { | ||||||
| 	if _, exists := config["default-runtime"]; exists { | 	runtimes := operator.GetRuntimes( | ||||||
| 		defaultRuntime := config["default-runtime"].(string) | 		operator.WithNvidiaRuntimeName(o.runtimeName), | ||||||
| 		if _, exists := nvidiaRuntimeBinaries[defaultRuntime]; exists { | 		operator.WithSetAsDefault(o.setAsDefault), | ||||||
| 			config["default-runtime"] = defaultDockerRuntime | 		operator.WithRoot(o.runtimeDir), | ||||||
|  | 	) | ||||||
|  | 	for name := range runtimes { | ||||||
|  | 		err := cfg.RemoveRuntime(name) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("failed to remove runtime %q: %v", name, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, exists := config["runtimes"]; exists { |  | ||||||
| 		runtimes := config["runtimes"].(map[string]interface{}) |  | ||||||
| 
 |  | ||||||
| 		for name := range nvidiaRuntimeBinaries { |  | ||||||
| 			delete(runtimes, name) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if len(runtimes) == 0 { |  | ||||||
| 			delete(config, "runtimes") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FlushConfig flushes the updated/reverted config out to disk
 |  | ||||||
| func FlushConfig(cfg map[string]interface{}, config string) error { |  | ||||||
| 	return docker.FlushConfig(cfg, config) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RestartDocker restarts docker depending on the value of restartModeFlag
 | // RestartDocker restarts docker depending on the value of restartModeFlag
 | ||||||
| func RestartDocker(o *options) error { | func RestartDocker(o *options) error { | ||||||
| 	switch o.restartMode { | 	switch o.restartMode { | ||||||
| @ -385,31 +383,3 @@ func SignalDocker(socket string) error { | |||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // getDefaultRuntime returns the default runtime for the configured options.
 |  | ||||||
| // If the configuration is invalid or the default runtimes should not be set
 |  | ||||||
| // the empty string is returned.
 |  | ||||||
| func (o options) getDefaultRuntime() string { |  | ||||||
| 	if o.setAsDefault == false { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return o.runtimeName |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // getRuntimeBinaries returns a map of runtime names to binary paths. This includes the
 |  | ||||||
| // renaming of the `nvidia` runtime as per the --runtime-class command line flag.
 |  | ||||||
| func (o options) getRuntimeBinaries() map[string]string { |  | ||||||
| 	runtimeBinaries := make(map[string]string) |  | ||||||
| 
 |  | ||||||
| 	for rt, bin := range nvidiaRuntimeBinaries { |  | ||||||
| 		runtime := rt |  | ||||||
| 		if o.runtimeName != "" && o.runtimeName != nvidiaExperimentalRuntimeName && runtime == defaultRuntimeName { |  | ||||||
| 			runtime = o.runtimeName |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		runtimeBinaries[runtime] = filepath.Join(o.runtimeDir, bin) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return runtimeBinaries |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/docker" | ||||||
| 	"github.com/stretchr/testify/require" | 	"github.com/stretchr/testify/require" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -60,9 +61,9 @@ func TestUpdateConfigDefaultRuntime(t *testing.T) { | |||||||
| 			runtimeDir:   runtimeDir, | 			runtimeDir:   runtimeDir, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		config := map[string]interface{}{} | 		config := docker.Config(map[string]interface{}{}) | ||||||
| 
 | 
 | ||||||
| 		err := UpdateConfig(config, o) | 		err := UpdateConfig(&config, o) | ||||||
| 		require.NoError(t, err, "%d: %v", i, tc) | 		require.NoError(t, err, "%d: %v", i, tc) | ||||||
| 
 | 
 | ||||||
| 		defaultRuntimeName := config["default-runtime"] | 		defaultRuntimeName := config["default-runtime"] | ||||||
| @ -74,7 +75,7 @@ func TestUpdateConfig(t *testing.T) { | |||||||
| 	const runtimeDir = "/test/runtime/dir" | 	const runtimeDir = "/test/runtime/dir" | ||||||
| 
 | 
 | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| 		config         map[string]interface{} | 		config         docker.Config | ||||||
| 		setAsDefault   bool | 		setAsDefault   bool | ||||||
| 		runtimeName    string | 		runtimeName    string | ||||||
| 		expectedConfig map[string]interface{} | 		expectedConfig map[string]interface{} | ||||||
| @ -254,7 +255,8 @@ func TestUpdateConfig(t *testing.T) { | |||||||
| 			runtimeName:  tc.runtimeName, | 			runtimeName:  tc.runtimeName, | ||||||
| 			runtimeDir:   runtimeDir, | 			runtimeDir:   runtimeDir, | ||||||
| 		} | 		} | ||||||
| 		err := UpdateConfig(tc.config, options) | 
 | ||||||
|  | 		err := UpdateConfig(&tc.config, options) | ||||||
| 		require.NoError(t, err, "%d: %v", i, tc) | 		require.NoError(t, err, "%d: %v", i, tc) | ||||||
| 
 | 
 | ||||||
| 		configContent, err := json.MarshalIndent(tc.config, "", "    ") | 		configContent, err := json.MarshalIndent(tc.config, "", "    ") | ||||||
| @ -269,7 +271,7 @@ func TestUpdateConfig(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| func TestRevertConfig(t *testing.T) { | func TestRevertConfig(t *testing.T) { | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| 		config         map[string]interface{} | 		config         docker.Config | ||||||
| 		expectedConfig map[string]interface{} | 		expectedConfig map[string]interface{} | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| @ -368,7 +370,7 @@ func TestRevertConfig(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for i, tc := range testCases { | 	for i, tc := range testCases { | ||||||
| 		err := RevertConfig(tc.config) | 		err := RevertConfig(&tc.config, &options{}) | ||||||
| 
 | 
 | ||||||
| 		require.NoError(t, err, "%d: %v", i, tc) | 		require.NoError(t, err, "%d: %v", i, tc) | ||||||
| 
 | 
 | ||||||
| @ -381,43 +383,3 @@ func TestRevertConfig(t *testing.T) { | |||||||
| 		require.EqualValues(t, string(expectedContent), string(configContent), "%d: %v", i, tc) | 		require.EqualValues(t, string(expectedContent), string(configContent), "%d: %v", i, tc) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func TestFlagsDefaultRuntime(t *testing.T) { |  | ||||||
| 	testCases := []struct { |  | ||||||
| 		setAsDefault bool |  | ||||||
| 		runtimeName  string |  | ||||||
| 		expected     string |  | ||||||
| 	}{ |  | ||||||
| 		{ |  | ||||||
| 			expected: "", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			runtimeName: "not-bool", |  | ||||||
| 			expected:    "", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			setAsDefault: false, |  | ||||||
| 			runtimeName:  "nvidia", |  | ||||||
| 			expected:     "", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			setAsDefault: true, |  | ||||||
| 			runtimeName:  "nvidia", |  | ||||||
| 			expected:     "nvidia", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			setAsDefault: true, |  | ||||||
| 			runtimeName:  "nvidia-experimental", |  | ||||||
| 			expected:     "nvidia-experimental", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for i, tc := range testCases { |  | ||||||
| 		f := options{ |  | ||||||
| 			setAsDefault: tc.setAsDefault, |  | ||||||
| 			runtimeName:  tc.runtimeName, |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		require.Equal(t, tc.expected, f.getDefaultRuntime(), "%d: %v", i, tc) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user