mirror of
				https://github.com/NVIDIA/nvidia-container-toolkit
				synced 2025-06-26 18:18:24 +00:00 
			
		
		
		
	Migrate cri-o config update to engine.Interface
Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
		
							parent
							
								
									9fff19da23
								
							
						
					
					
						commit
						3bac4fad09
					
				| @ -173,13 +173,14 @@ func (m command) configureCrio(c *cli.Context, config *config) error { | ||||
| 		configFilePath = defaultCrioConfigFilePath | ||||
| 	} | ||||
| 
 | ||||
| 	cfg, err := crio.LoadConfig(configFilePath) | ||||
| 	cfg, err := crio.New( | ||||
| 		crio.WithPath(configFilePath), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to load config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	err = crio.UpdateConfig( | ||||
| 		cfg, | ||||
| 	err = cfg.AddRuntime( | ||||
| 		config.nvidiaOptions.RuntimeName, | ||||
| 		config.nvidiaOptions.RuntimePath, | ||||
| 		config.nvidiaOptions.SetAsDefault, | ||||
| @ -196,12 +197,16 @@ func (m command) configureCrio(c *cli.Context, config *config) error { | ||||
| 		os.Stdout.WriteString(fmt.Sprintf("%s\n", output)) | ||||
| 		return nil | ||||
| 	} | ||||
| 	err = crio.FlushConfig(configFilePath, cfg) | ||||
| 	n, err := cfg.Save(configFilePath) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to flush config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	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 cri-o daemon be restarted.") | ||||
| 
 | ||||
| 	return nil | ||||
|  | ||||
| @ -20,62 +20,71 @@ import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine" | ||||
| 	"github.com/pelletier/go-toml" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| ) | ||||
| 
 | ||||
| // LoadConfig loads the cri-o config from disk
 | ||||
| func LoadConfig(config string) (*toml.Tree, error) { | ||||
| 	log.Infof("Loading config: %v", config) | ||||
| // Config represents the cri-o config
 | ||||
| type Config toml.Tree | ||||
| 
 | ||||
| 	info, err := os.Stat(config) | ||||
| 	if os.IsExist(err) && info.IsDir() { | ||||
| 		return nil, fmt.Errorf("config file is a directory") | ||||
| // New creates a cri-o config with the specified options
 | ||||
| func New(opts ...Option) (engine.Interface, error) { | ||||
| 	b := &builder{} | ||||
| 	for _, opt := range opts { | ||||
| 		opt(b) | ||||
| 	} | ||||
| 
 | ||||
| 	configFile := config | ||||
| 	if os.IsNotExist(err) { | ||||
| 		configFile = "/dev/null" | ||||
| 		log.Infof("Config file does not exist, creating new one") | ||||
| 	return b.build() | ||||
| } | ||||
| 
 | ||||
| 	cfg, err := toml.LoadFile(configFile) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| // AddRuntime adds a new runtime to the crio config
 | ||||
| func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error { | ||||
| 	if c == nil { | ||||
| 		return fmt.Errorf("config is nil") | ||||
| 	} | ||||
| 
 | ||||
| 	log.Infof("Successfully loaded config") | ||||
| 	config := (toml.Tree)(*c) | ||||
| 
 | ||||
| 	return cfg, nil | ||||
| } | ||||
| 
 | ||||
| // UpdateConfig updates the cri-o config to include the NVIDIA Container Runtime
 | ||||
| func UpdateConfig(config *toml.Tree, runtimeClass string, runtimePath string, setAsDefault bool) error { | ||||
| 	switch runc := config.Get("crio.runtime.runtimes.runc").(type) { | ||||
| 	case *toml.Tree: | ||||
| 		runc, _ = toml.Load(runc.String()) | ||||
| 		config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass}, runc) | ||||
| 		config.SetPath([]string{"crio", "runtime", "runtimes", name}, runc) | ||||
| 	} | ||||
| 
 | ||||
| 	config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass, "runtime_path"}, runtimePath) | ||||
| 	config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass, "runtime_type"}, "oci") | ||||
| 	config.SetPath([]string{"crio", "runtime", "runtimes", name, "runtime_path"}, path) | ||||
| 	config.SetPath([]string{"crio", "runtime", "runtimes", name, "runtime_type"}, "oci") | ||||
| 
 | ||||
| 	if setAsDefault { | ||||
| 		config.SetPath([]string{"crio", "runtime", "default_runtime"}, runtimeClass) | ||||
| 		config.SetPath([]string{"crio", "runtime", "default_runtime"}, name) | ||||
| 	} | ||||
| 
 | ||||
| 	*c = (Config)(config) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RevertConfig reverts the cri-o config to remove the NVIDIA Container Runtime
 | ||||
| func RevertConfig(config *toml.Tree, runtimeClass string) error { | ||||
| // DefaultRuntime returns the default runtime for the cri-o config
 | ||||
| func (c Config) DefaultRuntime() string { | ||||
| 	config := (toml.Tree)(c) | ||||
| 	if runtime, ok := config.GetPath([]string{"crio", "runtime", "default_runtime"}).(string); ok { | ||||
| 		if runtimeClass == runtime { | ||||
| 		return runtime | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| // RemoveRuntime removes a runtime from the cri-o config
 | ||||
| func (c *Config) RemoveRuntime(name string) error { | ||||
| 	if c == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	config := (toml.Tree)(*c) | ||||
| 	if runtime, ok := config.GetPath([]string{"crio", "runtime", "default_runtime"}).(string); ok { | ||||
| 		if runtime == name { | ||||
| 			config.DeletePath([]string{"crio", "runtime", "default_runtime"}) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	runtimeClassPath := []string{"crio", "runtime", "runtimes", runtimeClass} | ||||
| 	runtimeClassPath := []string{"crio", "runtime", "runtimes", name} | ||||
| 	config.DeletePath(runtimeClassPath) | ||||
| 	for i := 0; i < len(runtimeClassPath); i++ { | ||||
| 		remainingPath := runtimeClassPath[:len(runtimeClassPath)-i] | ||||
| @ -87,39 +96,36 @@ func RevertConfig(config *toml.Tree, runtimeClass string) error { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	*c = (Config)(config) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // FlushConfig flushes the updated/reverted config out to disk
 | ||||
| func FlushConfig(config string, cfg *toml.Tree) error { | ||||
| 	log.Infof("Flushing config") | ||||
| 
 | ||||
| 	output, err := cfg.ToTomlString() | ||||
| // Save writes the config to the specified path
 | ||||
| func (c Config) Save(path string) (int64, error) { | ||||
| 	config := (toml.Tree)(c) | ||||
| 	output, err := config.ToTomlString() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to convert to TOML: %v", err) | ||||
| 		return 0, fmt.Errorf("unable to convert to TOML: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	switch len(output) { | ||||
| 	case 0: | ||||
| 		err := os.Remove(config) | ||||
| 	if len(output) == 0 { | ||||
| 		err := os.Remove(path) | ||||
| 		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(config) | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 
 | ||||
| 	f, err := os.Create(path) | ||||
| 	if err != nil { | ||||
| 			return fmt.Errorf("unable to open '%v' for writing: %v", config, err) | ||||
| 		return 0, fmt.Errorf("unable to open '%v' for writing: %v", path, err) | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 
 | ||||
| 		_, err = f.WriteString(output) | ||||
| 	n, err := f.WriteString(output) | ||||
| 	if err != nil { | ||||
| 			return fmt.Errorf("unable to write output: %v", err) | ||||
| 		} | ||||
| 		return 0, fmt.Errorf("unable to write output: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	log.Infof("Successfully flushed config") | ||||
| 
 | ||||
| 	return nil | ||||
| 	return int64(n), err | ||||
| } | ||||
|  | ||||
							
								
								
									
										73
									
								
								internal/config/engine/crio/option.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								internal/config/engine/crio/option.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| /** | ||||
| # 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 crio | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/pelletier/go-toml" | ||||
| 	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 := toml.Tree{} | ||||
| 		return (*Config)(&empty), nil | ||||
| 	} | ||||
| 
 | ||||
| 	return loadConfig(b.path) | ||||
| } | ||||
| 
 | ||||
| // loadConfig loads the cri-o config from disk
 | ||||
| func loadConfig(config string) (*Config, error) { | ||||
| 	log.Infof("Loading config: %v", config) | ||||
| 
 | ||||
| 	info, err := os.Stat(config) | ||||
| 	if os.IsExist(err) && info.IsDir() { | ||||
| 		return nil, fmt.Errorf("config file is a directory") | ||||
| 	} | ||||
| 
 | ||||
| 	configFile := config | ||||
| 	if os.IsNotExist(err) { | ||||
| 		configFile = "/dev/null" | ||||
| 		log.Infof("Config file does not exist, creating new one") | ||||
| 	} | ||||
| 
 | ||||
| 	cfg, err := toml.LoadFile(configFile) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	log.Infof("Successfully loaded config") | ||||
| 
 | ||||
| 	return (*Config)(cfg), nil | ||||
| } | ||||
| @ -24,8 +24,9 @@ import ( | ||||
| 	"path/filepath" | ||||
| 
 | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/crio" | ||||
| 	"github.com/pelletier/go-toml" | ||||
| 	"github.com/NVIDIA/nvidia-container-toolkit/tools/container/operator" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| 	cli "github.com/urfave/cli/v2" | ||||
| ) | ||||
| @ -213,7 +214,9 @@ func setupHook(o *options) error { | ||||
| func setupConfig(o *options) error { | ||||
| 	log.Infof("Updating config file") | ||||
| 
 | ||||
| 	cfg, err := crio.LoadConfig(o.config) | ||||
| 	cfg, err := crio.New( | ||||
| 		crio.WithPath(o.config), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to load config: %v", err) | ||||
| 	} | ||||
| @ -223,10 +226,14 @@ func setupConfig(o *options) error { | ||||
| 		return fmt.Errorf("unable to update config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	err = crio.FlushConfig(o.config, cfg) | ||||
| 	log.Infof("Flushing cri-o config to %v", o.config) | ||||
| 	n, err := cfg.Save(o.config) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to flush config: %v", err) | ||||
| 	} | ||||
| 	if n == 0 { | ||||
| 		log.Infof("Config file is empty, removed") | ||||
| 	} | ||||
| 
 | ||||
| 	err = RestartCrio(o) | ||||
| 	if err != nil { | ||||
| @ -267,7 +274,9 @@ func cleanupHook(o *options) error { | ||||
| func cleanupConfig(o *options) error { | ||||
| 	log.Infof("Reverting config file modifications") | ||||
| 
 | ||||
| 	cfg, err := crio.LoadConfig(o.config) | ||||
| 	cfg, err := crio.New( | ||||
| 		crio.WithPath(o.config), | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to load config: %v", err) | ||||
| 	} | ||||
| @ -277,10 +286,14 @@ func cleanupConfig(o *options) error { | ||||
| 		return fmt.Errorf("unable to update config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	err = crio.FlushConfig(o.config, cfg) | ||||
| 	log.Infof("Flushing cri-o config to %v", o.config) | ||||
| 	n, err := cfg.Save(o.config) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("unable to flush config: %v", err) | ||||
| 	} | ||||
| 	if n == 0 { | ||||
| 		log.Infof("Config file is empty, removed") | ||||
| 	} | ||||
| 
 | ||||
| 	err = RestartCrio(o) | ||||
| 	if err != nil { | ||||
| @ -345,14 +358,36 @@ func generateOciHook(toolkitDir string) podmanHook { | ||||
| } | ||||
| 
 | ||||
| // UpdateConfig updates the cri-o config to include the NVIDIA Container Runtime
 | ||||
| func UpdateConfig(config *toml.Tree, o *options) error { | ||||
| 	runtimePath := filepath.Join(o.runtimeDir, "nvidia-container-runtime") | ||||
| 	return crio.UpdateConfig(config, o.runtimeClass, runtimePath, o.setAsDefault) | ||||
| func UpdateConfig(cfg engine.Interface, o *options) error { | ||||
| 	runtimes := operator.GetRuntimes( | ||||
| 		operator.WithNvidiaRuntimeName(o.runtimeClass), | ||||
| 		operator.WithSetAsDefault(o.setAsDefault), | ||||
| 		operator.WithRoot(o.runtimeDir), | ||||
| 	) | ||||
| 	for class, runtime := range runtimes { | ||||
| 		err := cfg.AddRuntime(class, runtime.Path, runtime.SetAsDefault) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("unable to update config for runtime class '%v': %v", class, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RevertConfig reverts the cri-o config to remove the NVIDIA Container Runtime
 | ||||
| func RevertConfig(config *toml.Tree, o *options) error { | ||||
| 	return crio.RevertConfig(config, o.runtimeClass) | ||||
| func RevertConfig(cfg engine.Interface, o *options) error { | ||||
| 	runtimes := operator.GetRuntimes( | ||||
| 		operator.WithNvidiaRuntimeName(o.runtimeClass), | ||||
| 		operator.WithSetAsDefault(o.setAsDefault), | ||||
| 		operator.WithRoot(o.runtimeDir), | ||||
| 	) | ||||
| 	for class := range runtimes { | ||||
| 		err := cfg.RemoveRuntime(class) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("unable to revert config for runtime class '%v': %v", class, err) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // RestartCrio restarts crio depending on the value of restartModeFlag
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user