Lock all possible kubecfg files at the beginning of ModifyConfig.
This commit is contained in:
		@@ -22,6 +22,7 @@ import (
 | 
				
			|||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -153,6 +154,17 @@ func NewDefaultPathOptions() *PathOptions {
 | 
				
			|||||||
// that means that this code will only write into a single file.  If you want to relativizePaths, you must provide a fully qualified path in any
 | 
					// that means that this code will only write into a single file.  If you want to relativizePaths, you must provide a fully qualified path in any
 | 
				
			||||||
// modified element.
 | 
					// modified element.
 | 
				
			||||||
func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error {
 | 
					func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error {
 | 
				
			||||||
 | 
						possibleSources := configAccess.GetLoadingPrecedence()
 | 
				
			||||||
 | 
						// sort the possible kubeconfig files so we always "lock" in the same order
 | 
				
			||||||
 | 
						// to avoid deadlock (note: this can fail w/ symlinks, but... come on).
 | 
				
			||||||
 | 
						sort.Strings(possibleSources)
 | 
				
			||||||
 | 
						for _, filename := range possibleSources {
 | 
				
			||||||
 | 
							if err := lockFile(filename); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							defer unlockFile(filename)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	startingConfig, err := configAccess.GetStartingConfig()
 | 
						startingConfig, err := configAccess.GetStartingConfig()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -186,7 +198,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			t := *cluster
 | 
								t := *cluster
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite.Clusters[key] = &t
 | 
								configToWrite.Clusters[key] = &t
 | 
				
			||||||
@@ -211,7 +226,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			configToWrite.Contexts[key] = context
 | 
								configToWrite.Contexts[key] = context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
								if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
				
			||||||
@@ -228,7 +246,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			t := *authInfo
 | 
								t := *authInfo
 | 
				
			||||||
			configToWrite.AuthInfos[key] = &t
 | 
								configToWrite.AuthInfos[key] = &t
 | 
				
			||||||
			configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile
 | 
								configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile
 | 
				
			||||||
@@ -251,7 +272,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			delete(configToWrite.Clusters, key)
 | 
								delete(configToWrite.Clusters, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
								if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
				
			||||||
@@ -267,7 +291,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			delete(configToWrite.Contexts, key)
 | 
								delete(configToWrite.Contexts, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
								if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
				
			||||||
@@ -283,7 +310,10 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
 | 
				
			|||||||
				destinationFile = configAccess.GetDefaultFilename()
 | 
									destinationFile = configAccess.GetDefaultFilename()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			configToWrite := GetConfigFromFileOrDie(destinationFile)
 | 
								configToWrite, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			delete(configToWrite.AuthInfos, key)
 | 
								delete(configToWrite.AuthInfos, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
								if err := WriteToFile(*configToWrite, destinationFile); err != nil {
 | 
				
			||||||
@@ -330,7 +360,10 @@ func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) er
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if configAccess.IsExplicitFile() {
 | 
						if configAccess.IsExplicitFile() {
 | 
				
			||||||
		file := configAccess.GetExplicitFile()
 | 
							file := configAccess.GetExplicitFile()
 | 
				
			||||||
		currConfig := GetConfigFromFileOrDie(file)
 | 
							currConfig, err := getConfigFromFile(file)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		currConfig.CurrentContext = newCurrentContext
 | 
							currConfig.CurrentContext = newCurrentContext
 | 
				
			||||||
		if err := WriteToFile(*currConfig, file); err != nil {
 | 
							if err := WriteToFile(*currConfig, file); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -341,7 +374,10 @@ func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) er
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if len(newCurrentContext) > 0 {
 | 
						if len(newCurrentContext) > 0 {
 | 
				
			||||||
		destinationFile := configAccess.GetDefaultFilename()
 | 
							destinationFile := configAccess.GetDefaultFilename()
 | 
				
			||||||
		config := GetConfigFromFileOrDie(destinationFile)
 | 
							config, err := getConfigFromFile(destinationFile)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		config.CurrentContext = newCurrentContext
 | 
							config.CurrentContext = newCurrentContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := WriteToFile(*config, destinationFile); err != nil {
 | 
							if err := WriteToFile(*config, destinationFile); err != nil {
 | 
				
			||||||
@@ -354,7 +390,10 @@ func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) er
 | 
				
			|||||||
	// we're supposed to be clearing the current context.  We need to find the first spot in the chain that is setting it and clear it
 | 
						// we're supposed to be clearing the current context.  We need to find the first spot in the chain that is setting it and clear it
 | 
				
			||||||
	for _, file := range configAccess.GetLoadingPrecedence() {
 | 
						for _, file := range configAccess.GetLoadingPrecedence() {
 | 
				
			||||||
		if _, err := os.Stat(file); err == nil {
 | 
							if _, err := os.Stat(file); err == nil {
 | 
				
			||||||
			currConfig := GetConfigFromFileOrDie(file)
 | 
								currConfig, err := getConfigFromFile(file)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if len(currConfig.CurrentContext) > 0 {
 | 
								if len(currConfig.CurrentContext) > 0 {
 | 
				
			||||||
				currConfig.CurrentContext = newCurrentContext
 | 
									currConfig.CurrentContext = newCurrentContext
 | 
				
			||||||
@@ -379,7 +418,10 @@ func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferenc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if configAccess.IsExplicitFile() {
 | 
						if configAccess.IsExplicitFile() {
 | 
				
			||||||
		file := configAccess.GetExplicitFile()
 | 
							file := configAccess.GetExplicitFile()
 | 
				
			||||||
		currConfig := GetConfigFromFileOrDie(file)
 | 
							currConfig, err := getConfigFromFile(file)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		currConfig.Preferences = newPrefs
 | 
							currConfig.Preferences = newPrefs
 | 
				
			||||||
		if err := WriteToFile(*currConfig, file); err != nil {
 | 
							if err := WriteToFile(*currConfig, file); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -389,7 +431,10 @@ func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferenc
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, file := range configAccess.GetLoadingPrecedence() {
 | 
						for _, file := range configAccess.GetLoadingPrecedence() {
 | 
				
			||||||
		currConfig := GetConfigFromFileOrDie(file)
 | 
							currConfig, err := getConfigFromFile(file)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !reflect.DeepEqual(currConfig.Preferences, newPrefs) {
 | 
							if !reflect.DeepEqual(currConfig.Preferences, newPrefs) {
 | 
				
			||||||
			currConfig.Preferences = newPrefs
 | 
								currConfig.Preferences = newPrefs
 | 
				
			||||||
@@ -404,15 +449,23 @@ func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferenc
 | 
				
			|||||||
	return errors.New("no config found to write preferences")
 | 
						return errors.New("no config found to write preferences")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit.  One exception, missing files result in empty configs, not an exit
 | 
					// getConfigFromFile tries to read a kubeconfig file and if it can't, returns an error.  One exception, missing files result in empty configs, not an error.
 | 
				
			||||||
func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config {
 | 
					func getConfigFromFile(filename string) (*clientcmdapi.Config, error) {
 | 
				
			||||||
	config, err := LoadFromFile(filename)
 | 
						config, err := LoadFromFile(filename)
 | 
				
			||||||
	if err != nil && !os.IsNotExist(err) {
 | 
						if err != nil && !os.IsNotExist(err) {
 | 
				
			||||||
		glog.FatalDepth(1, err)
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if config == nil {
 | 
						if config == nil {
 | 
				
			||||||
		return clientcmdapi.NewConfig()
 | 
							config = clientcmdapi.NewConfig()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return config, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit.  One exception, missing files result in empty configs, not an exit
 | 
				
			||||||
 | 
					func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config {
 | 
				
			||||||
 | 
						config, err := getConfigFromFile(filename)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.FatalDepth(1, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return config
 | 
						return config
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -382,12 +382,6 @@ func WriteToFile(config clientcmdapi.Config, filename string) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = lockFile(filename)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer unlockFile(filename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := ioutil.WriteFile(filename, content, 0600); err != nil {
 | 
						if err := ioutil.WriteFile(filename, content, 0600); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -397,6 +391,14 @@ func WriteToFile(config clientcmdapi.Config, filename string) error {
 | 
				
			|||||||
func lockFile(filename string) error {
 | 
					func lockFile(filename string) error {
 | 
				
			||||||
	// TODO: find a way to do this with actual file locks. Will
 | 
						// TODO: find a way to do this with actual file locks. Will
 | 
				
			||||||
	// probably need seperate solution for windows and linux.
 | 
						// probably need seperate solution for windows and linux.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make sure the dir exists before we try to create a lock file.
 | 
				
			||||||
 | 
						dir := filepath.Dir(filename)
 | 
				
			||||||
 | 
						if _, err := os.Stat(dir); os.IsNotExist(err) {
 | 
				
			||||||
 | 
							if err = os.MkdirAll(dir, 0755); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	f, err := os.OpenFile(lockName(filename), os.O_CREATE|os.O_EXCL, 0)
 | 
						f, err := os.OpenFile(lockName(filename), os.O_CREATE|os.O_EXCL, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user