diff --git a/pkg/controller/istiocsr/client.go b/pkg/controller/istiocsr/client.go index c23555ee2..77050f1eb 100644 --- a/pkg/controller/istiocsr/client.go +++ b/pkg/controller/istiocsr/client.go @@ -31,12 +31,12 @@ type ctrlClient interface { } func NewClient(m manager.Manager) (ctrlClient, error) { - c, err := BuildCustomClient(m) - if err != nil { - return nil, fmt.Errorf("failed to build custom client: %w", err) - } + // Use the manager's client directly instead of creating a custom client. + // The manager's client uses the manager's cache, which ensures the reconciler + // reads from the same cache that the controller's watches use, preventing + // cache mismatch issues. return &ctrlClientImpl{ - Client: c, + Client: m.GetClient(), }, nil } diff --git a/pkg/controller/istiocsr/controller.go b/pkg/controller/istiocsr/controller.go index 5099d166e..f91f9164e 100644 --- a/pkg/controller/istiocsr/controller.go +++ b/pkg/controller/istiocsr/controller.go @@ -15,6 +15,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" @@ -56,6 +57,50 @@ type Reconciler struct { // +kubebuilder:rbac:groups=operator.openshift.io,resources=istiocsrs/status,verbs=get;update;patch // +kubebuilder:rbac:groups=operator.openshift.io,resources=istiocsrs/finalizers,verbs=update +// NewCacheBuilder returns a cache builder function configured with label selectors +// for managed resources. This function is used by the manager to create its cache +// to ensure the reconciler reads from the same cache that the controller's watches use. +func NewCacheBuilder(config *rest.Config, opts cache.Options) (cache.Cache, error) { + managedResourceLabelReq, err := labels.NewRequirement(requestEnqueueLabelKey, selection.Equals, []string{requestEnqueueLabelValue}) + if err != nil { + return nil, fmt.Errorf("invalid cache label requirement for %q: %w", requestEnqueueLabelKey, err) + } + managedResourceLabelReqSelector := labels.NewSelector().Add(*managedResourceLabelReq) + + // Configure cache with label selectors for managed resources + opts.ByObject = map[client.Object]cache.ByObject{ + // Explicitly include IstioCSR to ensure the cache properly watches and syncs all IstioCSR objects + &v1alpha1.IstioCSR{}: {}, + // Resources managed by controller (with label selectors) + &certmanagerv1.Certificate{}: { + Label: managedResourceLabelReqSelector, + }, + &appsv1.Deployment{}: { + Label: managedResourceLabelReqSelector, + }, + &rbacv1.ClusterRole{}: { + Label: managedResourceLabelReqSelector, + }, + &rbacv1.ClusterRoleBinding{}: { + Label: managedResourceLabelReqSelector, + }, + &rbacv1.Role{}: { + Label: managedResourceLabelReqSelector, + }, + &rbacv1.RoleBinding{}: { + Label: managedResourceLabelReqSelector, + }, + &corev1.Service{}: { + Label: managedResourceLabelReqSelector, + }, + &corev1.ServiceAccount{}: { + Label: managedResourceLabelReqSelector, + }, + } + + return cache.New(config, opts) +} + // New returns a new Reconciler instance. func New(mgr ctrl.Manager) (*Reconciler, error) { c, err := NewClient(mgr) @@ -71,106 +116,6 @@ func New(mgr ctrl.Manager) (*Reconciler, error) { }, nil } -func BuildCustomClient(mgr ctrl.Manager) (client.Client, error) { - managedResourceLabelReq, _ := labels.NewRequirement(requestEnqueueLabelKey, selection.Equals, []string{requestEnqueueLabelValue}) - managedResourceLabelReqSelector := labels.NewSelector().Add(*managedResourceLabelReq) - - customCacheOpts := cache.Options{ - HTTPClient: mgr.GetHTTPClient(), - Scheme: mgr.GetScheme(), - Mapper: mgr.GetRESTMapper(), - ByObject: map[client.Object]cache.ByObject{ - &certmanagerv1.Certificate{}: { - Label: managedResourceLabelReqSelector, - }, - &appsv1.Deployment{}: { - Label: managedResourceLabelReqSelector, - }, - &rbacv1.ClusterRole{}: { - Label: managedResourceLabelReqSelector, - }, - &rbacv1.ClusterRoleBinding{}: { - Label: managedResourceLabelReqSelector, - }, - &rbacv1.Role{}: { - Label: managedResourceLabelReqSelector, - }, - &rbacv1.RoleBinding{}: { - Label: managedResourceLabelReqSelector, - }, - &corev1.Service{}: { - Label: managedResourceLabelReqSelector, - }, - &corev1.ServiceAccount{}: { - Label: managedResourceLabelReqSelector, - }, - }, - ReaderFailOnMissingInformer: true, - } - customCache, err := cache.New(mgr.GetConfig(), customCacheOpts) - if err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &v1alpha1.IstioCSR{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &certmanagerv1.Certificate{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &appsv1.Deployment{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &rbacv1.ClusterRole{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &rbacv1.ClusterRoleBinding{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &rbacv1.Role{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &rbacv1.RoleBinding{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &corev1.Service{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &corev1.ServiceAccount{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &corev1.Secret{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &corev1.ConfigMap{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &certmanagerv1.Issuer{}); err != nil { - return nil, err - } - if _, err = customCache.GetInformer(context.Background(), &certmanagerv1.ClusterIssuer{}); err != nil { - return nil, err - } - - err = mgr.Add(customCache) - if err != nil { - return nil, err - } - - customClient, err := client.New(mgr.GetConfig(), client.Options{ - HTTPClient: mgr.GetHTTPClient(), - Scheme: mgr.GetScheme(), - Mapper: mgr.GetRESTMapper(), - Cache: &client.CacheOptions{ - Reader: customCache, - }, - }) - if err != nil { - return nil, err - } - - return customClient, nil -} - // SetupWithManager sets up the controller with the Manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { mapFunc := func(ctx context.Context, obj client.Object) []reconcile.Request { diff --git a/pkg/operator/setup_manager.go b/pkg/operator/setup_manager.go index 99eca9cf5..dd35db768 100644 --- a/pkg/operator/setup_manager.go +++ b/pkg/operator/setup_manager.go @@ -10,11 +10,9 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientscheme "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" ctrllog "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -54,10 +52,9 @@ func NewControllerManager() (*Manager, error) { mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, - NewClient: func(config *rest.Config, options client.Options) (client.Client, error) { - return client.New(config, options) - }, - Logger: ctrl.Log.WithName("operator-manager"), + // Use custom cache builder to configure label selectors for managed resources + NewCache: istiocsr.NewCacheBuilder, + Logger: ctrl.Log.WithName("operator-manager"), }) if err != nil { return nil, fmt.Errorf("failed to create manager: %w", err)