mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
Merge pull request #5541 from deads2k/deads-expose-resolve-local-paths
allow any number of kubeconfig files
This commit is contained in:
commit
72699606a9
@ -33,31 +33,35 @@ import (
|
|||||||
const (
|
const (
|
||||||
RecommendedConfigPathFlag = "kubeconfig"
|
RecommendedConfigPathFlag = "kubeconfig"
|
||||||
RecommendedConfigPathEnvVar = "KUBECONFIG"
|
RecommendedConfigPathEnvVar = "KUBECONFIG"
|
||||||
|
|
||||||
|
DefaultEnvVarIndex = 0
|
||||||
|
DefaultCurrentDirIndex = 1
|
||||||
|
DefaultHomeDirIndex = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientConfigLoadingRules is a struct that calls our specific locations that are used for merging together a Config
|
// ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config
|
||||||
|
// Callers can put the chain together however they want, but we'd recommend:
|
||||||
|
// [0] = EnvVarPath
|
||||||
|
// [1] = CurrentDirectoryPath
|
||||||
|
// [2] = HomeDirectoryPath
|
||||||
|
// ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if thie file is not present
|
||||||
type ClientConfigLoadingRules struct {
|
type ClientConfigLoadingRules struct {
|
||||||
CommandLinePath string
|
ExplicitPath string
|
||||||
EnvVarPath string
|
Precedence []string
|
||||||
CurrentDirectoryPath string
|
|
||||||
HomeDirectoryPath string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to
|
// NewDefaultClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to
|
||||||
// use this constructor
|
// use this constructor
|
||||||
func NewClientConfigLoadingRules() *ClientConfigLoadingRules {
|
func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules {
|
||||||
return &ClientConfigLoadingRules{
|
return &ClientConfigLoadingRules{
|
||||||
CurrentDirectoryPath: ".kubeconfig",
|
Precedence: []string{os.Getenv(RecommendedConfigPathEnvVar), ".kubeconfig", os.Getenv("HOME") + "/.kube/.kubeconfig"},
|
||||||
HomeDirectoryPath: os.Getenv("HOME") + "/.kube/.kubeconfig",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load takes the loading rules and merges together a Config object based on following order.
|
// Load takes the loading rules and merges together a Config object based on following order.
|
||||||
// 1. CommandLinePath
|
// 1. ExplicitPath
|
||||||
// 2. EnvVarPath
|
// 2. Precedence slice
|
||||||
// 3. CurrentDirectoryPath
|
// A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored.
|
||||||
// 4. HomeDirectoryPath
|
|
||||||
// A missing CommandLinePath file produces an error. Empty filenames or other missing files are ignored.
|
|
||||||
// Read errors or files with non-deserializable content produce errors.
|
// Read errors or files with non-deserializable content produce errors.
|
||||||
// The first file to set a particular map key wins and map key's value is never changed.
|
// The first file to set a particular map key wins and map key's value is never changed.
|
||||||
// BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed.
|
// BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed.
|
||||||
@ -71,13 +75,14 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
|||||||
errlist := []error{}
|
errlist := []error{}
|
||||||
|
|
||||||
// Make sure a file we were explicitly told to use exists
|
// Make sure a file we were explicitly told to use exists
|
||||||
if len(rules.CommandLinePath) > 0 {
|
if len(rules.ExplicitPath) > 0 {
|
||||||
if _, err := os.Stat(rules.CommandLinePath); os.IsNotExist(err) {
|
if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {
|
||||||
errlist = append(errlist, fmt.Errorf("The config file %v does not exist", rules.CommandLinePath))
|
errlist = append(errlist, fmt.Errorf("The config file %v does not exist", rules.ExplicitPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeConfigFiles := []string{rules.CommandLinePath, rules.EnvVarPath, rules.CurrentDirectoryPath, rules.HomeDirectoryPath}
|
kubeConfigFiles := []string{rules.ExplicitPath}
|
||||||
|
kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
|
||||||
|
|
||||||
// first merge all of our maps
|
// first merge all of our maps
|
||||||
mapConfig := clientcmdapi.NewConfig()
|
mapConfig := clientcmdapi.NewConfig()
|
||||||
@ -85,7 +90,7 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
|||||||
if err := mergeConfigWithFile(mapConfig, file); err != nil {
|
if err := mergeConfigWithFile(mapConfig, file); err != nil {
|
||||||
errlist = append(errlist, err)
|
errlist = append(errlist, err)
|
||||||
}
|
}
|
||||||
if err := resolveLocalPaths(file, mapConfig); err != nil {
|
if err := ResolveLocalPaths(file, mapConfig); err != nil {
|
||||||
errlist = append(errlist, err)
|
errlist = append(errlist, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +101,7 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
|||||||
for i := len(kubeConfigFiles) - 1; i >= 0; i-- {
|
for i := len(kubeConfigFiles) - 1; i >= 0; i-- {
|
||||||
file := kubeConfigFiles[i]
|
file := kubeConfigFiles[i]
|
||||||
mergeConfigWithFile(nonMapConfig, file)
|
mergeConfigWithFile(nonMapConfig, file)
|
||||||
resolveLocalPaths(file, nonMapConfig)
|
ResolveLocalPaths(file, nonMapConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
|
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
|
||||||
@ -127,10 +132,10 @@ func mergeConfigWithFile(startingConfig *clientcmdapi.Config, filename string) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveLocalPaths resolves all relative paths in the config object with respect to the parent directory of the filename
|
// ResolveLocalPaths resolves all relative paths in the config object with respect to the parent directory of the filename
|
||||||
// this cannot be done directly inside of LoadFromFile because doing so there would make it impossible to load a file without
|
// this cannot be done directly inside of LoadFromFile because doing so there would make it impossible to load a file without
|
||||||
// modification of its contents.
|
// modification of its contents.
|
||||||
func resolveLocalPaths(filename string, config *clientcmdapi.Config) error {
|
func ResolveLocalPaths(filename string, config *clientcmdapi.Config) error {
|
||||||
if len(filename) == 0 {
|
if len(filename) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ var (
|
|||||||
|
|
||||||
func TestNonExistentCommandLineFile(t *testing.T) {
|
func TestNonExistentCommandLineFile(t *testing.T) {
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: "bogus_file",
|
ExplicitPath: "bogus_file",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
_, err := loadingRules.Load()
|
||||||
@ -92,9 +92,7 @@ func TestNonExistentCommandLineFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestToleratingMissingFiles(t *testing.T) {
|
func TestToleratingMissingFiles(t *testing.T) {
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
EnvVarPath: "bogus1",
|
Precedence: []string{"bogus1", "bogus2", "bogus3"},
|
||||||
CurrentDirectoryPath: "bogus2",
|
|
||||||
HomeDirectoryPath: "bogus3",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
_, err := loadingRules.Load()
|
||||||
@ -112,7 +110,7 @@ func TestErrorReadingFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: commandLineFile.Name(),
|
ExplicitPath: commandLineFile.Name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
_, err := loadingRules.Load()
|
||||||
@ -132,7 +130,7 @@ func TestErrorReadingNonFile(t *testing.T) {
|
|||||||
defer os.Remove(tmpdir)
|
defer os.Remove(tmpdir)
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: tmpdir,
|
ExplicitPath: tmpdir,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = loadingRules.Load()
|
_, err = loadingRules.Load()
|
||||||
@ -161,8 +159,8 @@ func TestConflictingCurrentContext(t *testing.T) {
|
|||||||
WriteToFile(mockEnvVarConfig, envVarFile.Name())
|
WriteToFile(mockEnvVarConfig, envVarFile.Name())
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: commandLineFile.Name(),
|
ExplicitPath: commandLineFile.Name(),
|
||||||
EnvVarPath: envVarFile.Name(),
|
Precedence: []string{envVarFile.Name()},
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
mergedConfig, err := loadingRules.Load()
|
||||||
@ -211,8 +209,8 @@ func TestResolveRelativePaths(t *testing.T) {
|
|||||||
WriteToFile(pathResolutionConfig2, configFile2)
|
WriteToFile(pathResolutionConfig2, configFile2)
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: configFile1,
|
ExplicitPath: configFile1,
|
||||||
EnvVarPath: configFile2,
|
Precedence: []string{configFile2},
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
mergedConfig, err := loadingRules.Load()
|
||||||
@ -286,8 +284,8 @@ func ExampleMergingSomeWithConflict() {
|
|||||||
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
|
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: commandLineFile.Name(),
|
ExplicitPath: commandLineFile.Name(),
|
||||||
EnvVarPath: envVarFile.Name(),
|
Precedence: []string{envVarFile.Name()},
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
mergedConfig, err := loadingRules.Load()
|
||||||
@ -346,10 +344,8 @@ func ExampleMergingEverythingNoConflicts() {
|
|||||||
WriteToFile(testConfigDelta, homeDirFile.Name())
|
WriteToFile(testConfigDelta, homeDirFile.Name())
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
loadingRules := ClientConfigLoadingRules{
|
||||||
CommandLinePath: commandLineFile.Name(),
|
ExplicitPath: commandLineFile.Name(),
|
||||||
EnvVarPath: envVarFile.Name(),
|
Precedence: []string{envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()},
|
||||||
CurrentDirectoryPath: currentDirFile.Name(),
|
|
||||||
HomeDirectoryPath: homeDirFile.Name(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
mergedConfig, err := loadingRules.Load()
|
||||||
|
@ -78,11 +78,11 @@ func testWriteAuthInfoFile(auth clientauth.Info, filename string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testBindClientConfig(cmd *cobra.Command) ClientConfig {
|
func testBindClientConfig(cmd *cobra.Command) ClientConfig {
|
||||||
loadingRules := NewClientConfigLoadingRules()
|
loadingRules := NewDefaultClientConfigLoadingRules()
|
||||||
loadingRules.EnvVarPath = ""
|
loadingRules.Precedence[DefaultEnvVarIndex] = ""
|
||||||
loadingRules.HomeDirectoryPath = ""
|
loadingRules.Precedence[DefaultCurrentDirIndex] = ""
|
||||||
loadingRules.CurrentDirectoryPath = ""
|
loadingRules.Precedence[DefaultHomeDirIndex] = ""
|
||||||
cmd.PersistentFlags().StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
|
cmd.PersistentFlags().StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
|
||||||
|
|
||||||
overrides := &ConfigOverrides{}
|
overrides := &ConfigOverrides{}
|
||||||
BindOverrideFlags(overrides, cmd.PersistentFlags(), RecommendedConfigOverrideFlags(""))
|
BindOverrideFlags(overrides, cmd.PersistentFlags(), RecommendedConfigOverrideFlags(""))
|
||||||
|
@ -322,9 +322,8 @@ func (f *Factory) ClientMapperForCommand(cmd *cobra.Command) resource.ClientMapp
|
|||||||
// 3. If the command line specifies one and the auth info specifies another, honor the command line technique.
|
// 3. If the command line specifies one and the auth info specifies another, honor the command line technique.
|
||||||
// 2. Use default values and potentially prompt for auth information
|
// 2. Use default values and potentially prompt for auth information
|
||||||
func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
|
func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
|
||||||
loadingRules := clientcmd.NewClientConfigLoadingRules()
|
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||||
loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
|
flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
|
||||||
flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
|
|
||||||
|
|
||||||
overrides := &clientcmd.ConfigOverrides{}
|
overrides := &clientcmd.ConfigOverrides{}
|
||||||
flagNames := clientcmd.RecommendedConfigOverrideFlags("")
|
flagNames := clientcmd.RecommendedConfigOverrideFlags("")
|
||||||
|
@ -19,7 +19,6 @@ package config
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -113,9 +112,8 @@ func (o viewOptions) validate() error {
|
|||||||
func (o *viewOptions) getStartingConfig() (*clientcmdapi.Config, string, error) {
|
func (o *viewOptions) getStartingConfig() (*clientcmdapi.Config, string, error) {
|
||||||
switch {
|
switch {
|
||||||
case o.merge.Value():
|
case o.merge.Value():
|
||||||
loadingRules := clientcmd.NewClientConfigLoadingRules()
|
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||||
loadingRules.EnvVarPath = os.Getenv("KUBECONFIG")
|
loadingRules.ExplicitPath = o.pathOptions.specifiedFile
|
||||||
loadingRules.CommandLinePath = o.pathOptions.specifiedFile
|
|
||||||
|
|
||||||
overrides := &clientcmd.ConfigOverrides{}
|
overrides := &clientcmd.ConfigOverrides{}
|
||||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
|
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
|
||||||
|
Loading…
Reference in New Issue
Block a user