/** # Copyright (c) Advanced Micro Devices, Inc. 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" "os" ) const ( runtimesKey = "runtimes" defaultRuntimeKey = "default-runtime" featuresKey = "features" //defaultCDISpecPath = "/etc/cdi" ) type dockerConfig map[string]interface{} func New(path string) (*dockerConfig, error){ return loadConfigFile(path) } func loadConfigFile(path string) (*dockerConfig, error) { //check if the file exists f, err := os.Stat(path) if os.IsExist(err) && f.IsDir(){ return nil, fmt.Errorf("file path is a directory") } config := dockerConfig{} if os.IsNotExist(err) { //return empty config return &config, nil } fmt.Printf("Loading configuration from: %v\n", path) readB, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading configuration file: %v | err: %v", path, err) } reader := bytes.NewReader(readB) err = json.NewDecoder(reader).Decode(&config) if err != nil { return nil, fmt.Errorf("error decoding configuration file: %v | err: %v", path, err) } return &config, nil } func (d *dockerConfig) ConfigRuntime(name string, path string, isDefault bool) error { if d == nil { return fmt.Errorf("configuration is empty") } currentCfg := *d //check any existing "runtimes" runtimes := map[string]interface{}{} if _, exists := currentCfg[runtimesKey]; exists { runtimes = currentCfg[runtimesKey].(map[string]interface{}) } runtimes[name] = map[string]interface{}{ "path": path, "args": []string{}, } currentCfg[runtimesKey] = runtimes // Enable CDI by default /* currentCfg[featuresKey] = map[string]interface{}{ "cdi": true, } */ if isDefault { currentCfg[defaultRuntimeKey] = name } *d = currentCfg return nil } // RemoveRuntime removes the runtime configuration and returns // an error and a do not update flag in case daemon.json doesn't need // to be updated func (d *dockerConfig) RemoveRuntime(name string) (error, bool){ //_ = os.RemoveAll(defaultCDISpecPath) if d == nil { return fmt.Errorf("configuration is empyt"), true } updated := false currentCfg := *daemon //check any existing "runtimes" if _, exists := currentCfg[runtimesKey]; exists{ runtimes := currentCfg[runtimesKey].(map[string]interface{}) delete(runtimes, name) delete(currentCfg, featuresKey) _, defExists := currentCfg[defaultRuntimeKey] if defExists { defCfg := currentCfg[defaultRuntimeKey].(string) if defCfg == name { delete(currentCfg, defaultRuntimeKey) } } if len(runtimes) == 0 { delete(currentCfg, runtimesKey) } updated = true } if updated { *d = currentCfg return nil, false } return nil, true } func (d dockerConfig) Update(path string) (int, error) { toWrite, err := json.MarshalIndent(d, ""," ") if err != nil{ return 0, fmt.Errorf("json marshal failed: %v", err) } if path == "" { num, err := os.Stdout.Write(toWrite) return num, err } f, err := os.Create(path) if err != nil { return 0, fmt.Errorf("failed to open file: %v | err: %v", path, err) } defer f.Close() return f.Write(toWrite) } }