diff --git a/cmd/controller-manager/app/controllermanager.go b/cmd/controller-manager/app/controllermanager.go index 9ffb1ba8d..9dcabdb69 100644 --- a/cmd/controller-manager/app/controllermanager.go +++ b/cmd/controller-manager/app/controllermanager.go @@ -199,24 +199,24 @@ func setupControllers(mgr controllerruntime.Manager, opts *options.Options, stop klog.Fatalf("Failed to setup policy controller: %v", err) } - bindingController := &binding.ResourceBindingController{ - Client: mgr.GetClient(), - DynamicClient: dynamicClientSet, - EventRecorder: mgr.GetEventRecorderFor(binding.ControllerName), - RESTMapper: mgr.GetRESTMapper(), - OverrideManager: overrideManager, - } + bindingController := binding.NewResourceBindingController( + mgr.GetClient(), + dynamicClientSet, + mgr.GetEventRecorderFor(binding.ControllerName), + mgr.GetRESTMapper(), + overrideManager, + ) if err := bindingController.SetupWithManager(mgr); err != nil { klog.Fatalf("Failed to setup binding controller: %v", err) } - clusterResourceBindingController := &binding.ClusterResourceBindingController{ - Client: mgr.GetClient(), - DynamicClient: dynamicClientSet, - EventRecorder: mgr.GetEventRecorderFor(binding.ClusterResourceBindingControllerName), - RESTMapper: mgr.GetRESTMapper(), - OverrideManager: overrideManager, - } + clusterResourceBindingController := binding.NewClusterResourceBindingController( + mgr.GetClient(), + dynamicClientSet, + mgr.GetEventRecorderFor(binding.ClusterResourceBindingControllerName), + mgr.GetRESTMapper(), + overrideManager, + ) if err := clusterResourceBindingController.SetupWithManager(mgr); err != nil { klog.Fatalf("Failed to setup cluster resource binding controller: %v", err) } diff --git a/pkg/controllers/binding/binding_controller.go b/pkg/controllers/binding/binding_controller.go index d20f44cd8..09ba36527 100644 --- a/pkg/controllers/binding/binding_controller.go +++ b/pkg/controllers/binding/binding_controller.go @@ -2,7 +2,9 @@ package binding import ( "context" + "fmt" + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -26,16 +28,34 @@ import ( "github.com/karmada-io/karmada/pkg/util/overridemanager" ) -// ControllerName is the controller name that will be used when reporting events. -const ControllerName = "binding-controller" +const ( + // ControllerName is the controller name that will be used when reporting events. + ControllerName = "binding-controller" + eventTypeFindOrphanWorks = "FindOrphanWorks" + eventTypeFetchWorkload = "FetchWorkload" + eventTypeTransformResourceBinding = "TransformResourceBinding" + eventTypeAggregateWorkStatuses = "AggregateWorkStatuses" +) // ResourceBindingController is to sync ResourceBinding. type ResourceBindingController struct { - client.Client // used to operate ResourceBinding resources. - DynamicClient dynamic.Interface // used to fetch arbitrary resources. - EventRecorder record.EventRecorder - RESTMapper meta.RESTMapper - OverrideManager overridemanager.OverrideManager + client client.Client // used to operate ResourceBinding resources. + dynamicClient dynamic.Interface // used to fetch arbitrary resources. + recorder record.EventRecorder + restMapper meta.RESTMapper + overrideManager overridemanager.OverrideManager +} + +// NewResourceBindingController creates a new ResourceBindingController. +func NewResourceBindingController(client client.Client, dynamicClient dynamic.Interface, recorder record.EventRecorder, restMapper meta.RESTMapper, overrideManager overridemanager.OverrideManager) *ResourceBindingController { + rbConroller := ResourceBindingController{ + client: client, + dynamicClient: dynamicClient, + recorder: recorder, + restMapper: restMapper, + overrideManager: overrideManager, + } + return &rbConroller } // Reconcile performs a full reconciliation for the object referred to by the Request. @@ -45,7 +65,7 @@ func (c *ResourceBindingController) Reconcile(ctx context.Context, req controlle klog.V(4).Infof("Reconciling ResourceBinding %s.", req.NamespacedName.String()) binding := &workv1alpha2.ResourceBinding{} - if err := c.Client.Get(context.TODO(), req.NamespacedName, binding); err != nil { + if err := c.client.Get(context.TODO(), req.NamespacedName, binding); err != nil { // The resource no longer exist, in which case we stop processing. if apierrors.IsNotFound(err) { return controllerruntime.Result{}, nil @@ -55,7 +75,7 @@ func (c *ResourceBindingController) Reconcile(ctx context.Context, req controlle } if !binding.DeletionTimestamp.IsZero() { - if err := helper.DeleteWorks(c.Client, labels.Set{ + if err := helper.DeleteWorks(c.client, labels.Set{ workv1alpha2.ResourceBindingNamespaceLabel: req.Namespace, workv1alpha2.ResourceBindingNameLabel: req.Name, }); err != nil { @@ -67,7 +87,10 @@ func (c *ResourceBindingController) Reconcile(ctx context.Context, req controlle isReady := helper.IsBindingReady(binding.Spec.Clusters) if !isReady { - klog.Infof("ResourceBinding(%s/%s) is not ready to sync", binding.GetNamespace(), binding.GetName()) + msg := fmt.Sprintf("ResourceBinding %s is not ready.", req.NamespacedName.String()) + klog.Infof(msg) + c.recorder.Event(binding, corev1.EventTypeWarning, "ResourceBindingNotReady", msg) + return controllerruntime.Result{}, nil } @@ -81,7 +104,7 @@ func (c *ResourceBindingController) removeFinalizer(rb *workv1alpha2.ResourceBin } controllerutil.RemoveFinalizer(rb, util.BindingControllerFinalizer) - err := c.Client.Update(context.TODO(), rb) + err := c.client.Update(context.TODO(), rb) if err != nil { return controllerruntime.Result{Requeue: true}, err } @@ -91,41 +114,47 @@ func (c *ResourceBindingController) removeFinalizer(rb *workv1alpha2.ResourceBin // syncBinding will sync resourceBinding to Works. func (c *ResourceBindingController) syncBinding(binding *workv1alpha2.ResourceBinding) (controllerruntime.Result, error) { clusterNames := helper.GetBindingClusterNames(binding.Spec.Clusters) - works, err := helper.FindOrphanWorks(c.Client, binding.Namespace, binding.Name, clusterNames, apiextensionsv1.NamespaceScoped) + works, err := helper.FindOrphanWorks(c.client, binding.Namespace, binding.Name, clusterNames, apiextensionsv1.NamespaceScoped) if err != nil { klog.Errorf("Failed to find orphan works by resourceBinding(%s/%s). Error: %v.", binding.GetNamespace(), binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFindOrphanWorks), err.Error()) return controllerruntime.Result{Requeue: true}, err } - err = helper.RemoveOrphanWorks(c.Client, works) + err = helper.RemoveOrphanWorks(c.client, works) if err != nil { klog.Errorf("Failed to remove orphan works by resourceBinding(%s/%s). Error: %v.", binding.GetNamespace(), binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFindOrphanWorks), err.Error()) return controllerruntime.Result{Requeue: true}, err } - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for resourceBinding(%s/%s). Error: %v.", binding.GetNamespace(), binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFetchWorkload), err.Error()) return controllerruntime.Result{Requeue: true}, err } - err = ensureWork(c.Client, workload, c.OverrideManager, binding, apiextensionsv1.NamespaceScoped) + err = ensureWork(c.client, workload, c.overrideManager, binding, apiextensionsv1.NamespaceScoped) if err != nil { klog.Errorf("Failed to transform resourceBinding(%s/%s) to works. Error: %v.", binding.GetNamespace(), binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeTransformResourceBinding), err.Error()) return controllerruntime.Result{Requeue: true}, err } - err = helper.AggregateResourceBindingWorkStatus(c.Client, binding, workload) + err = helper.AggregateResourceBindingWorkStatus(c.client, binding, workload) if err != nil { klog.Errorf("Failed to aggregate workStatuses to resourceBinding(%s/%s). Error: %v.", binding.GetNamespace(), binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeAggregateWorkStatuses), err.Error()) return controllerruntime.Result{Requeue: true}, err } klog.V(4).Infof("Update resourceBinding(%s/%s) with AggregatedStatus successfully.", binding.Namespace, binding.Name) + c.recorder.Event(binding, corev1.EventTypeNormal, "SyncResourceBinding", "ResourceBinding synced successfully") return controllerruntime.Result{}, nil } @@ -172,14 +201,14 @@ func (c *ResourceBindingController) newOverridePolicyFunc() handler.MapFunc { } bindingList := &workv1alpha2.ResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.client.List(context.TODO(), bindingList); err != nil { klog.Errorf("Failed to list resourceBindings, error: %v", err) return nil } var requests []reconcile.Request for _, binding := range bindingList.Items { - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for resourceBinding(%s/%s). Error: %v.", binding.Namespace, binding.Name, err) return nil @@ -201,14 +230,14 @@ func (c *ResourceBindingController) newReplicaSchedulingPolicyFunc() handler.Map return func(a client.Object) []reconcile.Request { rspResourceSelectors := a.(*policyv1alpha1.ReplicaSchedulingPolicy).Spec.ResourceSelectors bindingList := &workv1alpha2.ResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.client.List(context.TODO(), bindingList); err != nil { klog.Errorf("Failed to list resourceBindings, error: %v", err) return nil } var requests []reconcile.Request for _, binding := range bindingList.Items { - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for resourceBinding(%s/%s). Error: %v.", binding.Namespace, binding.Name, err) return nil diff --git a/pkg/controllers/binding/cluster_resource_binding_controller.go b/pkg/controllers/binding/cluster_resource_binding_controller.go index 1d9758879..cb77f37ff 100644 --- a/pkg/controllers/binding/cluster_resource_binding_controller.go +++ b/pkg/controllers/binding/cluster_resource_binding_controller.go @@ -2,7 +2,9 @@ package binding import ( "context" + "fmt" + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -31,11 +33,23 @@ const ClusterResourceBindingControllerName = "cluster-resource-binding-controlle // ClusterResourceBindingController is to sync ClusterResourceBinding. type ClusterResourceBindingController struct { - client.Client // used to operate ClusterResourceBinding resources. - DynamicClient dynamic.Interface // used to fetch arbitrary resources. - EventRecorder record.EventRecorder - RESTMapper meta.RESTMapper - OverrideManager overridemanager.OverrideManager + client client.Client // used to operate ClusterResourceBinding resources. + dynamicClient dynamic.Interface // used to fetch arbitrary resources. + recorder record.EventRecorder + restMapper meta.RESTMapper + overrideManager overridemanager.OverrideManager +} + +// NewClusterResourceBindingController creates a new ClusterResourceBindingController. +func NewClusterResourceBindingController(client client.Client, dynamicClient dynamic.Interface, recorder record.EventRecorder, restMapper meta.RESTMapper, overrideManager overridemanager.OverrideManager) *ClusterResourceBindingController { + crbConroller := ClusterResourceBindingController{ + client: client, + dynamicClient: dynamicClient, + recorder: recorder, + restMapper: restMapper, + overrideManager: overrideManager, + } + return &crbConroller } // Reconcile performs a full reconciliation for the object referred to by the Request. @@ -45,7 +59,7 @@ func (c *ClusterResourceBindingController) Reconcile(ctx context.Context, req co klog.V(4).Infof("Reconciling ClusterResourceBinding %s.", req.NamespacedName.String()) clusterResourceBinding := &workv1alpha2.ClusterResourceBinding{} - if err := c.Client.Get(context.TODO(), req.NamespacedName, clusterResourceBinding); err != nil { + if err := c.client.Get(context.TODO(), req.NamespacedName, clusterResourceBinding); err != nil { // The resource no longer exist, in which case we stop processing. if apierrors.IsNotFound(err) { return controllerruntime.Result{}, nil @@ -55,7 +69,7 @@ func (c *ClusterResourceBindingController) Reconcile(ctx context.Context, req co } if !clusterResourceBinding.DeletionTimestamp.IsZero() { - if err := helper.DeleteWorks(c.Client, labels.Set{ + if err := helper.DeleteWorks(c.client, labels.Set{ workv1alpha2.ClusterResourceBindingLabel: req.Name, }); err != nil { klog.Errorf("Failed to delete works related to %s: %v", clusterResourceBinding.GetName(), err) @@ -66,7 +80,10 @@ func (c *ClusterResourceBindingController) Reconcile(ctx context.Context, req co isReady := helper.IsBindingReady(clusterResourceBinding.Spec.Clusters) if !isReady { - klog.Infof("ClusterResourceBinding %s is not ready to sync", clusterResourceBinding.GetName()) + msg := fmt.Sprintf("ClusterResourceBinding %s is not ready to sync.", clusterResourceBinding.GetName()) + klog.Infof(msg) + c.recorder.Event(clusterResourceBinding, corev1.EventTypeWarning, "ResourceBindingNotReady", msg) + return controllerruntime.Result{}, nil } @@ -80,7 +97,7 @@ func (c *ClusterResourceBindingController) removeFinalizer(crb *workv1alpha2.Clu } controllerutil.RemoveFinalizer(crb, util.ClusterResourceBindingControllerFinalizer) - err := c.Client.Update(context.TODO(), crb) + err := c.client.Update(context.TODO(), crb) if err != nil { return controllerruntime.Result{Requeue: true}, err } @@ -90,33 +107,37 @@ func (c *ClusterResourceBindingController) removeFinalizer(crb *workv1alpha2.Clu // syncBinding will sync clusterResourceBinding to Works. func (c *ClusterResourceBindingController) syncBinding(binding *workv1alpha2.ClusterResourceBinding) (controllerruntime.Result, error) { clusterNames := helper.GetBindingClusterNames(binding.Spec.Clusters) - works, err := helper.FindOrphanWorks(c.Client, "", binding.Name, clusterNames, apiextensionsv1.ClusterScoped) + works, err := helper.FindOrphanWorks(c.client, "", binding.Name, clusterNames, apiextensionsv1.ClusterScoped) if err != nil { klog.Errorf("Failed to find orphan works by ClusterResourceBinding(%s). Error: %v.", binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFindOrphanWorks), err.Error()) return controllerruntime.Result{Requeue: true}, err } - err = helper.RemoveOrphanWorks(c.Client, works) + err = helper.RemoveOrphanWorks(c.client, works) if err != nil { klog.Errorf("Failed to remove orphan works by clusterResourceBinding(%s). Error: %v.", binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFindOrphanWorks), err.Error()) return controllerruntime.Result{Requeue: true}, err } - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for clusterResourceBinding(%s). Error: %v.", binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeFetchWorkload), err.Error()) return controllerruntime.Result{Requeue: true}, err } - err = ensureWork(c.Client, workload, c.OverrideManager, binding, apiextensionsv1.ClusterScoped) + err = ensureWork(c.client, workload, c.overrideManager, binding, apiextensionsv1.ClusterScoped) if err != nil { klog.Errorf("Failed to transform clusterResourceBinding(%s) to works. Error: %v.", binding.GetName(), err) return controllerruntime.Result{Requeue: true}, err } - err = helper.AggregateClusterResourceBindingWorkStatus(c.Client, binding, workload) + err = helper.AggregateClusterResourceBindingWorkStatus(c.client, binding, workload) if err != nil { klog.Errorf("Failed to aggregate workStatuses to clusterResourceBinding(%s). Error: %v.", binding.GetName(), err) + c.recorder.Event(binding, corev1.EventTypeWarning, fmt.Sprintf("Failed %s", eventTypeTransformResourceBinding), err.Error()) return controllerruntime.Result{Requeue: true}, err } klog.V(4).Infof("Update clusterResourceBinding(%s) with AggregatedStatus successfully.", binding.Name) @@ -164,14 +185,14 @@ func (c *ClusterResourceBindingController) newOverridePolicyFunc() handler.MapFu } bindingList := &workv1alpha2.ClusterResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.client.List(context.TODO(), bindingList); err != nil { klog.Errorf("Failed to list clusterResourceBindings, error: %v", err) return nil } var requests []reconcile.Request for _, binding := range bindingList.Items { - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for clusterResourceBinding(%s). Error: %v.", binding.Name, err) return nil @@ -193,14 +214,14 @@ func (c *ClusterResourceBindingController) newReplicaSchedulingPolicyFunc() hand return func(a client.Object) []reconcile.Request { rspResourceSelectors := a.(*policyv1alpha1.ReplicaSchedulingPolicy).Spec.ResourceSelectors bindingList := &workv1alpha2.ClusterResourceBindingList{} - if err := c.Client.List(context.TODO(), bindingList); err != nil { + if err := c.client.List(context.TODO(), bindingList); err != nil { klog.Errorf("Failed to list clusterResourceBindings, error: %v", err) return nil } var requests []reconcile.Request for _, binding := range bindingList.Items { - workload, err := helper.FetchWorkload(c.DynamicClient, c.RESTMapper, binding.Spec.Resource) + workload, err := helper.FetchWorkload(c.dynamicClient, c.restMapper, binding.Spec.Resource) if err != nil { klog.Errorf("Failed to fetch workload for clusterResourceBinding(%s). Error: %v.", binding.Name, err) return nil