diff --git a/controlplane/kubeadm/controllers/alias.go b/controlplane/kubeadm/controllers/alias.go index 71e55dd87357..b0733f825be5 100644 --- a/controlplane/kubeadm/controllers/alias.go +++ b/controlplane/kubeadm/controllers/alias.go @@ -20,6 +20,7 @@ import ( "context" "time" + "go.uber.org/zap" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -36,6 +37,7 @@ type KubeadmControlPlaneReconciler struct { EtcdDialTimeout time.Duration EtcdCallTimeout time.Duration + EtcdLogger *zap.Logger // WatchFilterValue is the label value used to filter events prior to reconciliation. WatchFilterValue string @@ -51,6 +53,7 @@ func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mg ClusterCache: r.ClusterCache, EtcdDialTimeout: r.EtcdDialTimeout, EtcdCallTimeout: r.EtcdCallTimeout, + EtcdLogger: r.EtcdLogger, WatchFilterValue: r.WatchFilterValue, RemoteConditionsGracePeriod: r.RemoteConditionsGracePeriod, }).SetupWithManager(ctx, mgr, options) diff --git a/controlplane/kubeadm/internal/cluster.go b/controlplane/kubeadm/internal/cluster.go index b414a5c10a34..1fddef3c8a21 100644 --- a/controlplane/kubeadm/internal/cluster.go +++ b/controlplane/kubeadm/internal/cluster.go @@ -24,6 +24,7 @@ import ( "time" "github.com/pkg/errors" + "go.uber.org/zap" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/rest" @@ -51,6 +52,7 @@ type Management struct { ClusterCache clustercache.ClusterCache EtcdDialTimeout time.Duration EtcdCallTimeout time.Duration + EtcdLogger *zap.Logger } // RemoteClusterConnectionError represents a failure to connect to a remote cluster. @@ -152,7 +154,7 @@ func (m *Management) GetWorkloadCluster(ctx context.Context, clusterKey client.O restConfig: restConfig, Client: c, CoreDNSMigrator: &CoreDNSMigrator{}, - etcdClientGenerator: NewEtcdClientGenerator(restConfig, tlsConfig, m.EtcdDialTimeout, m.EtcdCallTimeout), + etcdClientGenerator: NewEtcdClientGenerator(restConfig, tlsConfig, m.EtcdDialTimeout, m.EtcdCallTimeout, m.EtcdLogger), }, nil } diff --git a/controlplane/kubeadm/internal/controllers/controller.go b/controlplane/kubeadm/internal/controllers/controller.go index c03f9d2a1684..d5ad5aceeb4a 100644 --- a/controlplane/kubeadm/internal/controllers/controller.go +++ b/controlplane/kubeadm/internal/controllers/controller.go @@ -25,6 +25,7 @@ import ( "github.com/blang/semver/v4" "github.com/pkg/errors" + "go.uber.org/zap" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -84,6 +85,7 @@ type KubeadmControlPlaneReconciler struct { EtcdDialTimeout time.Duration EtcdCallTimeout time.Duration + EtcdLogger *zap.Logger // WatchFilterValue is the label value used to filter events prior to reconciliation. WatchFilterValue string @@ -146,6 +148,7 @@ func (r *KubeadmControlPlaneReconciler) SetupWithManager(ctx context.Context, mg ClusterCache: r.ClusterCache, EtcdDialTimeout: r.EtcdDialTimeout, EtcdCallTimeout: r.EtcdCallTimeout, + EtcdLogger: r.EtcdLogger, } } diff --git a/controlplane/kubeadm/internal/etcd/etcd.go b/controlplane/kubeadm/internal/etcd/etcd.go index 5b62d54a55fe..835f320256ca 100644 --- a/controlplane/kubeadm/internal/etcd/etcd.go +++ b/controlplane/kubeadm/internal/etcd/etcd.go @@ -24,9 +24,8 @@ import ( "github.com/pkg/errors" "go.etcd.io/etcd/api/v3/etcdserverpb" - "go.etcd.io/etcd/client/pkg/v3/logutil" clientv3 "go.etcd.io/etcd/client/v3" - "go.uber.org/zap/zapcore" + "go.uber.org/zap" "google.golang.org/grpc" kerrors "k8s.io/apimachinery/pkg/util/errors" @@ -133,14 +132,9 @@ type ClientConfiguration struct { TLSConfig *tls.Config DialTimeout time.Duration CallTimeout time.Duration + Logger *zap.Logger } -var ( - // Create the etcdClientLogger only once. Otherwise every call of clientv3.New - // would create its own logger which leads to a lot of memory allocations. - etcdClientLogger, _ = logutil.CreateDefaultZapLogger(zapcore.InfoLevel) -) - // NewClient creates a new etcd client with the given configuration. func NewClient(ctx context.Context, config ClientConfiguration) (*Client, error) { dialer, err := proxy.NewDialer(config.Proxy) @@ -155,7 +149,7 @@ func NewClient(ctx context.Context, config ClientConfiguration) (*Client, error) grpc.WithContextDialer(dialer.DialContextWithAddr), }, TLS: config.TLSConfig, - Logger: etcdClientLogger, + Logger: config.Logger, }) if err != nil { return nil, errors.Wrap(err, "unable to create etcd client") diff --git a/controlplane/kubeadm/internal/etcd_client_generator.go b/controlplane/kubeadm/internal/etcd_client_generator.go index db42b072503f..ace3f37fc20b 100644 --- a/controlplane/kubeadm/internal/etcd_client_generator.go +++ b/controlplane/kubeadm/internal/etcd_client_generator.go @@ -23,6 +23,7 @@ import ( "time" "github.com/pkg/errors" + "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" @@ -44,7 +45,7 @@ type clientCreator func(ctx context.Context, endpoint string) (*etcd.Client, err var errEtcdNodeConnection = errors.New("failed to connect to etcd node") // NewEtcdClientGenerator returns a new etcdClientGenerator instance. -func NewEtcdClientGenerator(restConfig *rest.Config, tlsConfig *tls.Config, etcdDialTimeout, etcdCallTimeout time.Duration) *EtcdClientGenerator { +func NewEtcdClientGenerator(restConfig *rest.Config, tlsConfig *tls.Config, etcdDialTimeout, etcdCallTimeout time.Duration, etcdLogger *zap.Logger) *EtcdClientGenerator { ecg := &EtcdClientGenerator{restConfig: restConfig, tlsConfig: tlsConfig} ecg.createClient = func(ctx context.Context, endpoint string) (*etcd.Client, error) { @@ -60,6 +61,7 @@ func NewEtcdClientGenerator(restConfig *rest.Config, tlsConfig *tls.Config, etcd TLSConfig: tlsConfig, DialTimeout: etcdDialTimeout, CallTimeout: etcdCallTimeout, + Logger: etcdLogger, }) } diff --git a/controlplane/kubeadm/internal/etcd_client_generator_test.go b/controlplane/kubeadm/internal/etcd_client_generator_test.go index 1f668c6d1480..cf4737f2aa0a 100644 --- a/controlplane/kubeadm/internal/etcd_client_generator_test.go +++ b/controlplane/kubeadm/internal/etcd_client_generator_test.go @@ -25,7 +25,9 @@ import ( . "github.com/onsi/gomega" "github.com/pkg/errors" "go.etcd.io/etcd/api/v3/etcdserverpb" + "go.etcd.io/etcd/client/pkg/v3/logutil" clientv3 "go.etcd.io/etcd/client/v3" + "go.uber.org/zap/zapcore" "k8s.io/client-go/rest" "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd" @@ -33,12 +35,13 @@ import ( ) var ( - subject *EtcdClientGenerator + subject *EtcdClientGenerator + etcdClientLogger, _ = logutil.CreateDefaultZapLogger(zapcore.InfoLevel) ) func TestNewEtcdClientGenerator(t *testing.T) { g := NewWithT(t) - subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0) + subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0, etcdClientLogger) g.Expect(subject.createClient).To(Not(BeNil())) } @@ -90,7 +93,7 @@ func TestFirstAvailableNode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0) + subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0, etcdClientLogger) subject.createClient = tt.cc client, err := subject.forFirstAvailableNode(ctx, tt.nodes) @@ -212,7 +215,7 @@ func TestForLeader(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0) + subject = NewEtcdClientGenerator(&rest.Config{}, &tls.Config{MinVersion: tls.VersionTLS12}, 0, 0, etcdClientLogger) subject.createClient = tt.cc client, err := subject.forLeader(ctx, tt.nodes) diff --git a/controlplane/kubeadm/main.go b/controlplane/kubeadm/main.go index 62415248c855..b307e3698356 100644 --- a/controlplane/kubeadm/main.go +++ b/controlplane/kubeadm/main.go @@ -27,6 +27,8 @@ import ( "github.com/pkg/errors" "github.com/spf13/pflag" + "go.etcd.io/etcd/client/pkg/v3/logutil" + "go.uber.org/zap/zapcore" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -102,6 +104,7 @@ var ( skipCRDMigrationPhases []string etcdDialTimeout time.Duration etcdCallTimeout time.Duration + etcdLogLevel string ) func init() { @@ -192,6 +195,9 @@ func InitFlags(fs *pflag.FlagSet) { fs.DurationVar(&etcdCallTimeout, "etcd-call-timeout-duration", etcd.DefaultCallTimeout, "Duration that the etcd client waits at most for read and write operations to etcd.") + fs.StringVar(&etcdLogLevel, "etcd-client-log-level", zapcore.InfoLevel.String(), + "Logging level for etcd client. Possible values are: debug, info, warn, error, dpanic, panic, fatal.") + flags.AddManagerOptions(fs, &managerOptions) feature.MutableGates.AddFlag(fs) @@ -420,6 +426,14 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { os.Exit(1) } + zapLogLevel, err := zapcore.ParseLevel(etcdLogLevel) + if err != nil { + setupLog.Error(err, "Unable to parse etcd log level") + } + etcdLogger, err := logutil.CreateDefaultZapLogger(zapLogLevel) + if err != nil { + setupLog.Error(err, "unable to create etcd logger") + } if err := (&kubeadmcontrolplanecontrollers.KubeadmControlPlaneReconciler{ Client: mgr.GetClient(), SecretCachingClient: secretCachingClient, @@ -427,6 +441,7 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { WatchFilterValue: watchFilterValue, EtcdDialTimeout: etcdDialTimeout, EtcdCallTimeout: etcdCallTimeout, + EtcdLogger: etcdLogger, RemoteConditionsGracePeriod: remoteConditionsGracePeriod, }).SetupWithManager(ctx, mgr, concurrency(kubeadmControlPlaneConcurrency)); err != nil { setupLog.Error(err, "unable to create controller", "controller", "KubeadmControlPlane")