diff --git a/internal/controller/operator/controlplane/dapr_controlplane_controller.go b/internal/controller/operator/controlplane/dapr_controlplane_controller.go index 0e91a9b..d78be1d 100644 --- a/internal/controller/operator/controlplane/dapr_controlplane_controller.go +++ b/internal/controller/operator/controlplane/dapr_controlplane_controller.go @@ -20,6 +20,8 @@ import ( "context" "fmt" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/openshift" "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/helm" @@ -50,7 +52,7 @@ func NewReconciler(ctx context.Context, manager ctrlRt.Manager, o helm.Options) rec := Reconciler{} rec.l = ctrlRt.Log.WithName("dapr-controlplane-controller") - rec.Client = c + rec.client = c rec.Scheme = manager.GetScheme() rec.ClusterType = controller.ClusterTypeVanilla rec.manager = manager @@ -94,8 +96,7 @@ func NewReconciler(ctx context.Context, manager ctrlRt.Manager, o helm.Options) // +kubebuilder:rbac:groups=operator.dapr.io,resources=daprinstances/status,verbs=get type Reconciler struct { - *client.Client - + client *client.Client Scheme *runtime.Scheme ClusterType controller.ClusterType actions []Action @@ -106,6 +107,10 @@ type Reconciler struct { recorder record.EventRecorder } +func (r *Reconciler) Client() *client.Client { + return r.client +} + func (r *Reconciler) init(ctx context.Context) error { c := ctrlRt.NewControllerManagedBy(r.manager) @@ -115,7 +120,7 @@ func (r *Reconciler) init(ctx context.Context) error { ))) for i := range r.actions { - b, err := r.actions[i].Configure(ctx, r.Client, c) + b, err := r.actions[i].Configure(ctx, r.Client(), c) if err != nil { //nolint:wrapcheck return err @@ -124,7 +129,9 @@ func (r *Reconciler) init(ctx context.Context) error { c = b } - ct, err := c.Build(r) + objRec := reconcile.AsReconciler[*daprApi.DaprControlPlane](r.manager.GetClient(), r) + + ct, err := c.Build(objRec) if err != nil { return fmt.Errorf("failure building the application controller for DaprControlPlane resource: %w", err) } diff --git a/internal/controller/operator/controlplane/dapr_controlplane_controller_reconcile.go b/internal/controller/operator/controlplane/dapr_controlplane_controller_reconcile.go index ce46891..1ddbc80 100644 --- a/internal/controller/operator/controlplane/dapr_controlplane_controller_reconcile.go +++ b/internal/controller/operator/controlplane/dapr_controlplane_controller_reconcile.go @@ -23,6 +23,8 @@ import ( "os" "sort" + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller/reconciler" + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller" "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/conditions" @@ -32,34 +34,26 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" - ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - daprvApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" + daprApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" ) -func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprControlPlane) (ctrl.Result, error) { l := log.FromContext(ctx) - l.Info("Reconciling", "resource", req.NamespacedName.String()) rr := ReconciliationRequest{ - Client: r.Client, + Client: r.Client(), NamespacedName: types.NamespacedName{ - Name: req.Name, - Namespace: req.Namespace, + Name: res.Name, + Namespace: res.Namespace, }, ClusterType: r.ClusterType, Reconciler: r, - Resource: &daprvApi.DaprControlPlane{}, + Resource: res, } - err := r.Get(ctx, req.NamespacedName, rr.Resource) - if err != nil { - if k8serrors.IsNotFound(err) { - // no CR found anymore, maybe deleted - return ctrl.Result{}, nil - } - } + l.Info("Reconciling", "resource", rr.NamespacedName.String()) // by default, the controller expect the DaprControlPlane resource to be created // in the same namespace where it runs, if not fallback to the default namespace @@ -69,7 +63,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu ns = controller.NamespaceDefault } - if req.Name != DaprControlPlaneResourceName || req.Namespace != ns { + if res.Name != DaprControlPlaneResourceName || res.Namespace != ns { rr.Resource.Status.Phase = conditions.TypeError meta.SetStatusCondition(&rr.Resource.Status.Conditions, metav1.Condition{ @@ -82,7 +76,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu ns), }) - err = r.Status().Update(ctx, rr.Resource) + err := r.Client().Status().Update(ctx, rr.Resource) if err != nil && k8serrors.IsConflict(err) { l.Info(err.Error()) @@ -92,42 +86,23 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, fmt.Errorf("error updating DaprControlPlane resource: %w", err) } - //nolint:nestif + //nolint:wrapcheck if rr.Resource.ObjectMeta.DeletionTimestamp.IsZero() { - // - // Add finalizer - // - if ctrlutil.AddFinalizer(rr.Resource, DaprControlPlaneFinalizerName) { - if err := r.Update(ctx, rr.Resource); err != nil { - if k8serrors.IsConflict(err) { - return ctrl.Result{}, fmt.Errorf("conflict when adding finalizer to %s: %w", req.NamespacedName, err) - } - - return ctrl.Result{}, fmt.Errorf("failure adding finalizer to %s: %w", req.NamespacedName, err) - } + err := reconciler.AddFinalizer(ctx, r.Client(), rr.Resource, DaprControlPlaneFinalizerName) + if err != nil { + return ctrl.Result{}, err } } else { - // // Cleanup leftovers if needed - // for i := len(r.actions) - 1; i >= 0; i-- { if err := r.actions[i].Cleanup(ctx, &rr); err != nil { - //nolint:wrapcheck return ctrl.Result{}, err } } - // - // Handle finalizer - // - if ctrlutil.RemoveFinalizer(rr.Resource, DaprControlPlaneFinalizerName) { - if err := r.Update(ctx, rr.Resource); err != nil { - if k8serrors.IsConflict(err) { - return ctrl.Result{}, fmt.Errorf("conflict when removing finalizer to %s: %w", req.NamespacedName, err) - } - - return ctrl.Result{}, fmt.Errorf("failure removing finalizer from %s: %w", req.NamespacedName, err) - } + err := reconciler.RemoveFinalizer(ctx, r.Client(), rr.Resource, DaprControlPlaneFinalizerName) + if err != nil { + return ctrl.Result{}, err } return ctrl.Result{}, nil @@ -174,7 +149,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Update status // - err = r.Status().Update(ctx, rr.Resource) + err := r.Client().Status().Update(ctx, rr.Resource) if err != nil && k8serrors.IsConflict(err) { l.Info(err.Error()) return ctrl.Result{Requeue: true}, nil diff --git a/internal/controller/operator/instance/dapr_instance_controller.go b/internal/controller/operator/instance/dapr_instance_controller.go index fe02eba..a9ca77e 100644 --- a/internal/controller/operator/instance/dapr_instance_controller.go +++ b/internal/controller/operator/instance/dapr_instance_controller.go @@ -37,7 +37,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/predicate" - daprvApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" + daprApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller" "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller/client" "github.com/go-logr/logr" @@ -56,7 +56,7 @@ func NewReconciler(ctx context.Context, manager ctrlRt.Manager, o helm.Options) rec := Reconciler{} rec.l = ctrlRt.Log.WithName("dapr-instance-controller") - rec.Client = c + rec.client = c rec.Scheme = manager.GetScheme() rec.ClusterType = controller.ClusterTypeVanilla rec.manager = manager @@ -126,8 +126,7 @@ func NewReconciler(ctx context.Context, manager ctrlRt.Manager, o helm.Options) // +kubebuilder:rbac:groups=dapr.io,resources=subscriptions/finalizers,verbs=* type Reconciler struct { - *client.Client - + client *client.Client Scheme *runtime.Scheme ClusterType controller.ClusterType actions []Action @@ -138,16 +137,20 @@ type Reconciler struct { recorder record.EventRecorder } +func (r *Reconciler) Client() *client.Client { + return r.client +} + func (r *Reconciler) init(ctx context.Context) error { c := ctrlRt.NewControllerManagedBy(r.manager) - c = c.For(&daprvApi.DaprInstance{}, builder.WithPredicates( + c = c.For(&daprApi.DaprInstance{}, builder.WithPredicates( predicate.Or( predicate.GenerationChangedPredicate{}, ))) for i := range r.actions { - b, err := r.actions[i].Configure(ctx, r.Client, c) + b, err := r.actions[i].Configure(ctx, r.Client(), c) if err != nil { //nolint:wrapcheck return err @@ -156,7 +159,9 @@ func (r *Reconciler) init(ctx context.Context) error { c = b } - ct, err := c.Build(r) + objRec := reconcile.AsReconciler[*daprApi.DaprInstance](r.manager.GetClient(), r) + + ct, err := c.Build(objRec) if err != nil { return fmt.Errorf("failure building the application controller for DaprInstance resource: %w", err) } diff --git a/internal/controller/operator/instance/dapr_instance_controller_reconcile.go b/internal/controller/operator/instance/dapr_instance_controller_reconcile.go index 1db4bf1..4be0b16 100644 --- a/internal/controller/operator/instance/dapr_instance_controller_reconcile.go +++ b/internal/controller/operator/instance/dapr_instance_controller_reconcile.go @@ -23,6 +23,8 @@ import ( "os" "sort" + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller/reconciler" + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller" "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/conditions" @@ -32,25 +34,23 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" - ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - daprvApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" + daprApi "github.com/dapr-sandbox/dapr-kubernetes-operator/api/operator/v1alpha1" ) -func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *Reconciler) Reconcile(ctx context.Context, res *daprApi.DaprInstance) (ctrl.Result, error) { l := log.FromContext(ctx) - l.Info("Reconciling", "resource", req.NamespacedName.String()) rr := ReconciliationRequest{ - Client: r.Client, + Client: r.Client(), NamespacedName: types.NamespacedName{ - Name: req.Name, - Namespace: req.Namespace, + Name: res.Name, + Namespace: res.Namespace, }, ClusterType: r.ClusterType, Reconciler: r, - Resource: &daprvApi.DaprInstance{}, + Resource: res, Chart: r.c, Overrides: map[string]interface{}{ "dapr_operator": map[string]interface{}{"runAsNonRoot": "true"}, @@ -60,13 +60,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu }, } - err := r.Get(ctx, req.NamespacedName, rr.Resource) - if err != nil { - if k8serrors.IsNotFound(err) { - // no CR found anymore, maybe deleted - return ctrl.Result{}, nil - } - } + l.Info("Reconciling", "resource", rr.NamespacedName.String()) // by default, the controller expect the DaprInstance resource to be created // in the same namespace where it runs, if not fallback to the default namespace @@ -76,7 +70,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu ns = controller.NamespaceDefault } - if req.Name != DaprInstanceResourceName || req.Namespace != ns { + if res.Name != DaprInstanceResourceName || res.Namespace != ns { rr.Resource.Status.Phase = conditions.TypeError meta.SetStatusCondition(&rr.Resource.Status.Conditions, metav1.Condition{ @@ -89,7 +83,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu ns), }) - err = r.Status().Update(ctx, rr.Resource) + err := r.Client().Status().Update(ctx, rr.Resource) if err != nil && k8serrors.IsConflict(err) { l.Info(err.Error()) @@ -99,42 +93,23 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, fmt.Errorf("error updating DaprInstance resource: %w", err) } - //nolint:nestif + //nolint:wrapcheck if rr.Resource.ObjectMeta.DeletionTimestamp.IsZero() { - // - // Add finalizer - // - if ctrlutil.AddFinalizer(rr.Resource, DaprInstanceFinalizerName) { - if err := r.Update(ctx, rr.Resource); err != nil { - if k8serrors.IsConflict(err) { - return ctrl.Result{}, fmt.Errorf("conflict when adding finalizer to %s: %w", req.NamespacedName, err) - } - - return ctrl.Result{}, fmt.Errorf("failure adding finalizer to %s: %w", req.NamespacedName, err) - } + err := reconciler.AddFinalizer(ctx, r.Client(), rr.Resource, DaprInstanceFinalizerName) + if err != nil { + return ctrl.Result{}, err } } else { - // // Cleanup leftovers if needed - // for i := len(r.actions) - 1; i >= 0; i-- { if err := r.actions[i].Cleanup(ctx, &rr); err != nil { - //nolint:wrapcheck return ctrl.Result{}, err } } - // - // Handle finalizer - // - if ctrlutil.RemoveFinalizer(rr.Resource, DaprInstanceFinalizerName) { - if err := r.Update(ctx, rr.Resource); err != nil { - if k8serrors.IsConflict(err) { - return ctrl.Result{}, fmt.Errorf("conflict when removing finalizer to %s: %w", req.NamespacedName, err) - } - - return ctrl.Result{}, fmt.Errorf("failure removing finalizer from %s: %w", req.NamespacedName, err) - } + err := reconciler.RemoveFinalizer(ctx, r.Client(), rr.Resource, DaprInstanceFinalizerName) + if err != nil { + return ctrl.Result{}, err } return ctrl.Result{}, nil @@ -181,7 +156,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Update status // - err = r.Status().Update(ctx, rr.Resource) + err := r.Client().Status().Update(ctx, rr.Resource) if err != nil && k8serrors.IsConflict(err) { l.Info(err.Error()) diff --git a/pkg/controller/reconciler/types.go b/pkg/controller/reconciler/types.go new file mode 100644 index 0000000..6dffdda --- /dev/null +++ b/pkg/controller/reconciler/types.go @@ -0,0 +1,56 @@ +package reconciler + +import ( + "context" + "fmt" + + "github.com/dapr-sandbox/dapr-kubernetes-operator/pkg/controller/client" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/builder" + ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" + ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +type Reconciler interface { + Client() *client.Client +} + +type Action[T any] interface { + Configure(ctx context.Context, c *client.Client, b *builder.Builder) (*builder.Builder, error) + Run(ctx context.Context, rc *T) error + Cleanup(ctx context.Context, rc *T) error +} + +func AddFinalizer(ctx context.Context, client ctrlClient.Client, o ctrlClient.Object, name string) error { + if !ctrlutil.AddFinalizer(o, name) { + return nil + } + + err := client.Update(ctx, o) + if k8serrors.IsConflict(err) { + return fmt.Errorf("conflict when adding finalizer to %s/%s: %w", o.GetNamespace(), o.GetName(), err) + } + + if err != nil { + return fmt.Errorf("failure adding finalizer to %s/%s: %w", o.GetNamespace(), o.GetName(), err) + } + + return nil +} + +func RemoveFinalizer(ctx context.Context, client ctrlClient.Client, o ctrlClient.Object, name string) error { + if !ctrlutil.RemoveFinalizer(o, name) { + return nil + } + + err := client.Update(ctx, o) + if k8serrors.IsConflict(err) { + return fmt.Errorf("conflict when removing finalizer to %s/%s: %w", o.GetNamespace(), o.GetName(), err) + } + + if err != nil { + return fmt.Errorf("failure removing finalizer from %s/%s: %w", o.GetNamespace(), o.GetName(), err) + } + + return nil +}