diff --git a/staging/src/k8s.io/client-go/tools/clientcmd/loader.go b/staging/src/k8s.io/client-go/tools/clientcmd/loader.go index 44de1d41d83..b75737f1c90 100644 --- a/staging/src/k8s.io/client-go/tools/clientcmd/loader.go +++ b/staging/src/k8s.io/client-go/tools/clientcmd/loader.go @@ -128,6 +128,28 @@ type ClientConfigLoadingRules struct { // WarnIfAllMissing indicates whether the configuration files pointed by KUBECONFIG environment variable are present or not. // In case of missing files, it warns the user about the missing files. WarnIfAllMissing bool + + // Warner is the warning log callback to use in case of missing files. + Warner WarningHandler +} + +// WarningHandler allows to set the logging function to use +type WarningHandler func(error) + +func (handler WarningHandler) Warn(err error) { + if handler == nil { + klog.V(1).Info(err) + } else { + handler(err) + } +} + +type MissingConfigError struct { + Missing []string +} + +func (c MissingConfigError) Error() string { + return fmt.Sprintf("Config not found: %s", strings.Join(c.Missing, ", ")) } // ClientConfigLoadingRules implements the ClientConfigLoader interface. @@ -219,7 +241,7 @@ func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) { } if rules.WarnIfAllMissing && len(missingList) > 0 && len(kubeconfigs) == 0 { - klog.Warningf("Config not found: %s", strings.Join(missingList, ", ")) + rules.Warner.Warn(MissingConfigError{Missing: missingList}) } // first merge all of our maps diff --git a/staging/src/k8s.io/client-go/tools/clientcmd/loader_test.go b/staging/src/k8s.io/client-go/tools/clientcmd/loader_test.go index aa6741b8b5f..df6b3021c9a 100644 --- a/staging/src/k8s.io/client-go/tools/clientcmd/loader_test.go +++ b/staging/src/k8s.io/client-go/tools/clientcmd/loader_test.go @@ -18,6 +18,7 @@ package clientcmd import ( "bytes" + "flag" "fmt" "os" "path" @@ -32,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest" + "k8s.io/klog/v2" ) var ( @@ -120,14 +122,77 @@ func TestNonExistentCommandLineFile(t *testing.T) { } func TestToleratingMissingFiles(t *testing.T) { + envVarValue := "bogus" loadingRules := ClientConfigLoadingRules{ - Precedence: []string{"bogus1", "bogus2", "bogus3"}, + Precedence: []string{"bogus1", "bogus2", "bogus3"}, + WarnIfAllMissing: true, + Warner: func(err error) { klog.Warning(err) }, } + buffer := &bytes.Buffer{} + + klog.LogToStderr(false) + klog.SetOutput(buffer) + _, err := loadingRules.Load() if err != nil { t.Fatalf("Unexpected error: %v", err) } + klog.Flush() + expectedLog := fmt.Sprintf("Config not found: %s", envVarValue) + if !strings.Contains(buffer.String(), expectedLog) { + t.Fatalf("expected log: \"%s\"", expectedLog) + } +} + +func TestWarningMissingFiles(t *testing.T) { + envVarValue := "bogus" + os.Setenv(RecommendedConfigPathEnvVar, envVarValue) + loadingRules := NewDefaultClientConfigLoadingRules() + + buffer := &bytes.Buffer{} + + flags := &flag.FlagSet{} + klog.InitFlags(flags) + flags.Set("v", "1") + klog.LogToStderr(false) + klog.SetOutput(buffer) + + _, err := loadingRules.Load() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + klog.Flush() + + expectedLog := fmt.Sprintf("Config not found: %s", envVarValue) + if !strings.Contains(buffer.String(), expectedLog) { + t.Fatalf("expected log: \"%s\"", expectedLog) + } +} + +func TestNoWarningMissingFiles(t *testing.T) { + envVarValue := "bogus" + os.Setenv(RecommendedConfigPathEnvVar, envVarValue) + loadingRules := NewDefaultClientConfigLoadingRules() + + buffer := &bytes.Buffer{} + + flags := &flag.FlagSet{} + klog.InitFlags(flags) + flags.Set("v", "0") + klog.LogToStderr(false) + klog.SetOutput(buffer) + + _, err := loadingRules.Load() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + klog.Flush() + + logNotExpected := fmt.Sprintf("Config not found: %s", envVarValue) + if strings.Contains(buffer.String(), logNotExpected) { + t.Fatalf("log not expected: \"%s\"", logNotExpected) + } } func TestErrorReadingFile(t *testing.T) {