Add warning log callback in client-go loading rules (#117233)
* Add warning log callback in client-go loading rules This provides a way to consumers use their own custom warning mechanisms instead default klog warning. * Use typed error instead plain string * Fix interface change in unit test
This commit is contained in:
		@@ -128,6 +128,28 @@ type ClientConfigLoadingRules struct {
 | 
				
			|||||||
	// WarnIfAllMissing indicates whether the configuration files pointed by KUBECONFIG environment variable are present or not.
 | 
						// 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.
 | 
						// In case of missing files, it warns the user about the missing files.
 | 
				
			||||||
	WarnIfAllMissing bool
 | 
						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.
 | 
					// 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 {
 | 
						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
 | 
						// first merge all of our maps
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ package clientcmd
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
@@ -32,6 +33,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
						clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
				
			||||||
	clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
 | 
						clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
 | 
				
			||||||
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -120,14 +122,77 @@ func TestNonExistentCommandLineFile(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestToleratingMissingFiles(t *testing.T) {
 | 
					func TestToleratingMissingFiles(t *testing.T) {
 | 
				
			||||||
 | 
						envVarValue := "bogus"
 | 
				
			||||||
	loadingRules := ClientConfigLoadingRules{
 | 
						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()
 | 
						_, err := loadingRules.Load()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("Unexpected error: %v", err)
 | 
							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) {
 | 
					func TestErrorReadingFile(t *testing.T) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user