-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package controllers | ||
|
||
// Importing necessary packages. | ||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
) | ||
|
||
// minSyncPeriod defines the minimum synchronization period | ||
const minSyncPeriod = 30 * time.Second | ||
|
||
type ScheduleOption func(options *ScheduleOptions) | ||
|
||
// scheduleReconciler is a wrapper for Reconciler interface from controller-runtime package. | ||
type scheduleReconciler struct { | ||
reconciler reconcile.Reconciler | ||
|
||
syncPeriod time.Duration | ||
} | ||
|
||
type ScheduleOptions struct { | ||
// define the synchronization interval. | ||
SyncPeriod time.Duration | ||
} | ||
|
||
// defaultOpts set default values for ScheduleOptions | ||
func defaultOpts(opts ScheduleOptions) ScheduleOptions { | ||
if opts.SyncPeriod <= minSyncPeriod { | ||
opts.SyncPeriod = minSyncPeriod | ||
} | ||
|
||
return opts | ||
} | ||
|
||
// NewScheduleReconciler creates a new scheduleReconciler with the provided Reconciler and ScheduleOptions. | ||
func NewScheduleReconciler(r reconcile.Reconciler, opts ...ScheduleOption) reconcile.Reconciler { | ||
options := ScheduleOptions{} | ||
for _, option := range opts { | ||
option(&options) | ||
} | ||
options = defaultOpts(options) | ||
|
||
return &scheduleReconciler{ | ||
reconciler: r, | ||
syncPeriod: options.SyncPeriod, | ||
} | ||
} | ||
|
||
// Reconcile is the method that will be called whenever an event occurs that the Reconciler should handle. | ||
// It calls the Reconcile method of the embedded Reconciler and adjusts the RequeueAfter | ||
func (s *scheduleReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { | ||
if s.reconciler == nil { | ||
return reconcile.Result{}, fmt.Errorf("reconciler should not be empty") | ||
} | ||
|
||
result, err := s.reconciler.Reconcile(ctx, request) | ||
if err != nil { | ||
return result, err | ||
} | ||
|
||
// set the requeue after to the SyncPeriod of the scheduleReconciler | ||
// ensure that the reconcile run when the result does not require requeue | ||
if !result.Requeue && result.RequeueAfter <= 0 { | ||
result.RequeueAfter = s.syncPeriod | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package controllers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
. "github.com/onsi/gomega" | ||
"github.com/onsi/gomega/types" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
) | ||
|
||
func TestNewScheduleReconciler(t *testing.T) { | ||
r := NewScheduleReconciler(nil) | ||
sr, ok := r.(*scheduleReconciler) | ||
|
||
g := NewGomegaWithT(t) | ||
g.Expect(ok).To(BeTrue()) | ||
g.Expect(sr.syncPeriod).To(Equal(minSyncPeriod)) | ||
|
||
r = NewScheduleReconciler(reconcile.Func(emptyReconciler), func(options *ScheduleOptions) { | ||
options.SyncPeriod = 1 * time.Minute | ||
}) | ||
sr, ok = r.(*scheduleReconciler) | ||
g.Expect(ok).To(BeTrue()) | ||
g.Expect(sr.syncPeriod).To(Equal(1 * time.Minute)) | ||
} | ||
|
||
func TestSyncReconcilerReconcile(t *testing.T) { | ||
cases := map[string]struct { | ||
r reconcile.Reconciler | ||
eval func(types.Gomega, reconcile.Result, error) | ||
}{ | ||
"nil reconciler": { | ||
r: nil, | ||
eval: func(g types.Gomega, result reconcile.Result, err error) { | ||
g.Expect(result.IsZero()).To(BeTrue()) | ||
g.Expect(err).NotTo(BeNil()) | ||
}, | ||
}, | ||
"empty reconciler": { | ||
r: reconcile.Func(emptyReconciler), | ||
eval: func(g types.Gomega, result reconcile.Result, err error) { | ||
g.Expect(result.Requeue).To(BeFalse()) | ||
g.Expect(result.RequeueAfter).To(Equal(1 * time.Minute)) | ||
g.Expect(err).To(BeNil()) | ||
}, | ||
}, | ||
"reconciler with error": { | ||
r: reconcile.Func(reconcilerWithError), | ||
eval: func(g types.Gomega, result reconcile.Result, err error) { | ||
g.Expect(result.IsZero()).To(BeTrue()) | ||
g.Expect(err).NotTo(BeNil()) | ||
}, | ||
}, | ||
"reconciler with requeue": { | ||
r: reconcile.Func(reconcilerWithRequeue), | ||
eval: func(g types.Gomega, result reconcile.Result, err error) { | ||
g.Expect(result.Requeue).To(BeTrue()) | ||
g.Expect(result.RequeueAfter).To(Equal(time.Duration(0))) | ||
g.Expect(err).To(BeNil()) | ||
}, | ||
}, | ||
"reconciler with requeue after": { | ||
r: reconcile.Func(reconcilerWithRequeueAfter), | ||
eval: func(g types.Gomega, result reconcile.Result, err error) { | ||
g.Expect(result.Requeue).To(BeFalse()) | ||
g.Expect(result.RequeueAfter).To(Equal(2 * time.Minute)) | ||
g.Expect(err).To(BeNil()) | ||
}, | ||
}, | ||
} | ||
|
||
for name, item := range cases { | ||
t.Run(name, func(t *testing.T) { | ||
g := NewGomegaWithT(t) | ||
r := NewScheduleReconciler(item.r, func(options *ScheduleOptions) { | ||
options.SyncPeriod = 1 * time.Minute | ||
}) | ||
result, err := r.Reconcile(context.Background(), reconcile.Request{}) | ||
item.eval(g, result, err) | ||
}) | ||
} | ||
} | ||
|
||
func emptyReconciler(_ context.Context, _ reconcile.Request) (reconcile.Result, error) { | ||
return reconcile.Result{}, nil | ||
} | ||
|
||
func reconcilerWithError(_ context.Context, _ reconcile.Request) (reconcile.Result, error) { | ||
result := reconcile.Result{} | ||
|
||
return result, fmt.Errorf("test error") | ||
} | ||
|
||
func reconcilerWithRequeue(_ context.Context, _ reconcile.Request) (reconcile.Result, error) { | ||
result := reconcile.Result{Requeue: true} | ||
|
||
return result, nil | ||
} | ||
|
||
func reconcilerWithRequeueAfter(_ context.Context, _ reconcile.Request) (reconcile.Result, error) { | ||
result := reconcile.Result{RequeueAfter: 2 * time.Minute} | ||
|
||
return result, nil | ||
} |