From afd9a51f433a5ba070c26bb76142c731aec23a4c Mon Sep 17 00:00:00 2001 From: Tom Wieczorek Date: Wed, 2 Oct 2024 14:05:14 +0200 Subject: [PATCH] Add API extensions clients to client factory Signed-off-by: Tom Wieczorek --- internal/testutil/kube_client.go | 27 +++++++++----- pkg/applier/stack.go | 19 ++++------ .../controller/etcd_member_reconciler.go | 18 ++++------ pkg/kubernetes/client.go | 36 ++++++++++++++++--- 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/internal/testutil/kube_client.go b/internal/testutil/kube_client.go index f60d54904f91..c31a6691ccd6 100644 --- a/internal/testutil/kube_client.go +++ b/internal/testutil/kube_client.go @@ -29,6 +29,9 @@ import ( "github.com/k0sproject/k0s/pkg/constant" kubeutil "github.com/k0sproject/k0s/pkg/kubernetes" + apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + apiextensionsfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" + apiextensionsscheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -51,6 +54,7 @@ func NewFakeClientFactory(objects ...runtime.Object) *FakeClientFactory { // Create a scheme containing all the kinds and types that k0s knows about. scheme := runtime.NewScheme() utilruntime.Must(kubernetesscheme.AddToScheme(scheme)) + utilruntime.Must(apiextensionsscheme.AddToScheme(scheme)) utilruntime.Must(k0sscheme.AddToScheme(scheme)) // Create a dynamic fake client that can deal with all that. @@ -66,21 +70,24 @@ func NewFakeClientFactory(objects ...runtime.Object) *FakeClientFactory { // transform between typed and unstructured objects. tracker := fakeclient.TypedObjectTrackerFrom(scheme, fakeDynamic) kubeClients := fakeclient.NewClientset[kubernetesfake.Clientset](fakeDiscovery, tracker) + apiExtensionsClients := fakeclient.NewClientset[apiextensionsfake.Clientset](fakeDiscovery, tracker) k0sClients := fakeclient.NewClientset[k0sfake.Clientset](fakeDiscovery, tracker) return &FakeClientFactory{ - DynamicClient: fakeDynamic, - Client: kubeClients, - DiscoveryClient: memory.NewMemCacheClient(fakeDiscovery), - K0sClient: k0sClients, + DynamicClient: fakeDynamic, + Client: kubeClients, + DiscoveryClient: memory.NewMemCacheClient(fakeDiscovery), + APIExtensionsClient: apiExtensionsClients, + K0sClient: k0sClients, } } type FakeClientFactory struct { - DynamicClient *dynamicfake.FakeDynamicClient - Client *kubernetesfake.Clientset - DiscoveryClient discovery.CachedDiscoveryInterface - K0sClient *k0sfake.Clientset + DynamicClient *dynamicfake.FakeDynamicClient + Client kubernetes.Interface + DiscoveryClient discovery.CachedDiscoveryInterface + APIExtensionsClient *apiextensionsfake.Clientset + K0sClient *k0sfake.Clientset } func (f *FakeClientFactory) GetClient() (kubernetes.Interface, error) { @@ -95,6 +102,10 @@ func (f *FakeClientFactory) GetDiscoveryClient() (discovery.CachedDiscoveryInter return f.DiscoveryClient, nil } +func (f *FakeClientFactory) GetAPIExtensionsClient() (apiextensionsclientset.Interface, error) { + return f.APIExtensionsClient, nil +} + func (f *FakeClientFactory) GetK0sClient() (k0sclientset.Interface, error) { return f.K0sClient, nil } diff --git a/pkg/applier/stack.go b/pkg/applier/stack.go index f2d7348b0c20..8f2ed6d29c43 100644 --- a/pkg/applier/stack.go +++ b/pkg/applier/stack.go @@ -29,8 +29,7 @@ import ( "github.com/k0sproject/k0s/pkg/kubernetes" "github.com/k0sproject/k0s/pkg/kubernetes/watch" - extensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - extensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiErrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -155,11 +154,7 @@ func (s *Stack) Apply(ctx context.Context, prune bool) error { // waitForCRD waits 5 seconds for a CRD to become established on a best-effort basis. func (s *Stack) waitForCRD(ctx context.Context, crdName string) { - config, err := s.Clients.GetRESTConfig() - if err != nil { - return - } - client, err := extensionsclient.NewForConfig(config) + client, err := s.Clients.GetAPIExtensionsClient() if err != nil { return } @@ -167,13 +162,13 @@ func (s *Stack) waitForCRD(ctx context.Context, crdName string) { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - _ = watch.CRDs(client.CustomResourceDefinitions()). + _ = watch.CRDs(client.ApiextensionsV1().CustomResourceDefinitions()). WithObjectName(crdName). WithErrorCallback(watch.IsRetryable). - Until(ctx, func(item *extensionsv1.CustomResourceDefinition) (bool, error) { + Until(ctx, func(item *apiextensionsv1.CustomResourceDefinition) (bool, error) { for _, cond := range item.Status.Conditions { - if cond.Type == extensionsv1.Established { - return cond.Status == extensionsv1.ConditionTrue, nil + if cond.Type == apiextensionsv1.Established { + return cond.Status == apiextensionsv1.ConditionTrue, nil } } return false, nil @@ -450,7 +445,7 @@ func (s *Stack) prepareResource(resource *unstructured.Unstructured) { func isCRD(resource *unstructured.Unstructured) bool { gvk := resource.GroupVersionKind() - return gvk.Group == extensionsv1.GroupName && gvk.Kind == "CustomResourceDefinition" + return gvk.Group == apiextensionsv1.GroupName && gvk.Kind == "CustomResourceDefinition" } func generateResourceID(resource unstructured.Unstructured) string { diff --git a/pkg/component/controller/etcd_member_reconciler.go b/pkg/component/controller/etcd_member_reconciler.go index c4832126e8bd..ededc9dcb8a1 100644 --- a/pkg/component/controller/etcd_member_reconciler.go +++ b/pkg/component/controller/etcd_member_reconciler.go @@ -34,11 +34,9 @@ import ( kubeutil "github.com/k0sproject/k0s/pkg/kubernetes" "github.com/k0sproject/k0s/pkg/kubernetes/watch" "github.com/sirupsen/logrus" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - extensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - extclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" ) var _ manager.Component = (*EtcdMemberReconciler)(nil) @@ -126,18 +124,14 @@ func (e *EtcdMemberReconciler) Stop() error { } func (e *EtcdMemberReconciler) waitForCRD(ctx context.Context) error { - rc, err := e.clientFactory.GetRESTConfig() - if err != nil { - return err - } - ec, err := extclient.NewForConfig(rc) + client, err := e.clientFactory.GetAPIExtensionsClient() if err != nil { return err } var lastObservedVersion string log := logrus.WithField("component", "etcdMemberReconciler") log.Info("waiting to see EtcdMember CRD ready") - return watch.CRDs(ec.CustomResourceDefinitions()). + return watch.CRDs(client.ApiextensionsV1().CustomResourceDefinitions()). WithObjectName(fmt.Sprintf("%s.%s", "etcdmembers", "etcd.k0sproject.io")). WithErrorCallback(func(err error) (time.Duration, error) { if retryAfter, e := watch.IsRetryable(err); e == nil { @@ -159,12 +153,12 @@ func (e *EtcdMemberReconciler) waitForCRD(ctx context.Context) error { ) return retryAfter, nil }). - Until(ctx, func(item *extensionsv1.CustomResourceDefinition) (bool, error) { + Until(ctx, func(item *apiextensionsv1.CustomResourceDefinition) (bool, error) { lastObservedVersion = item.ResourceVersion for _, cond := range item.Status.Conditions { - if cond.Type == extensionsv1.Established { + if cond.Type == apiextensionsv1.Established { log.Infof("EtcdMember CRD status: %s", cond.Status) - return cond.Status == extensionsv1.ConditionTrue, nil + return cond.Status == apiextensionsv1.ConditionTrue, nil } } diff --git a/pkg/kubernetes/client.go b/pkg/kubernetes/client.go index bee49d19b23f..405d90f85873 100644 --- a/pkg/kubernetes/client.go +++ b/pkg/kubernetes/client.go @@ -24,6 +24,7 @@ import ( cfgClient "github.com/k0sproject/k0s/pkg/client/clientset/typed/k0s/v1beta1" "github.com/k0sproject/k0s/pkg/constant" + apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" "k8s.io/client-go/discovery" "k8s.io/client-go/discovery/cached/memory" "k8s.io/client-go/dynamic" @@ -37,6 +38,7 @@ type ClientFactoryInterface interface { GetClient() (kubernetes.Interface, error) GetDynamicClient() (dynamic.Interface, error) GetDiscoveryClient() (discovery.CachedDiscoveryInterface, error) + GetAPIExtensionsClient() (apiextensionsclientset.Interface, error) GetK0sClient() (k0sclientset.Interface, error) GetConfigClient() (cfgClient.ClusterConfigInterface, error) // Deprecated: Use [ClientFactoryInterface.GetK0sClient] instead. GetRESTConfig() (*rest.Config, error) @@ -49,11 +51,12 @@ type ClientFactoryInterface interface { type ClientFactory struct { LoadRESTConfig func() (*rest.Config, error) - client kubernetes.Interface - dynamicClient dynamic.Interface - discoveryClient discovery.CachedDiscoveryInterface - k0sClient k0sclientset.Interface - restConfig *rest.Config + client kubernetes.Interface + dynamicClient dynamic.Interface + discoveryClient discovery.CachedDiscoveryInterface + apiExtensionsClient apiextensionsclientset.Interface + k0sClient k0sclientset.Interface + restConfig *rest.Config mutex sync.Mutex } @@ -128,6 +131,29 @@ func (c *ClientFactory) GetDiscoveryClient() (discovery.CachedDiscoveryInterface return cachedClient, nil } +func (c *ClientFactory) GetAPIExtensionsClient() (apiextensionsclientset.Interface, error) { + c.mutex.Lock() + defer c.mutex.Unlock() + + if c.apiExtensionsClient != nil { + return c.apiExtensionsClient, nil + } + + config, err := c.getRESTConfig() + if err != nil { + return nil, err + } + + client, err := apiextensionsclientset.NewForConfig(config) + if err != nil { + return nil, err + } + + c.apiExtensionsClient = client + + return client, nil +} + func (c *ClientFactory) GetK0sClient() (k0sclientset.Interface, error) { c.mutex.Lock() defer c.mutex.Unlock()