Skip to content

Commit 032e581

Browse files
committed
controller: sched: update status only if needed
So far updating the scheduler status was done in every reconcilation iteration even if the spec fields reflected the same values. This commit saves a copy of the initial resource status and uses it as a reference to identify if the resource requires a status update or not and act accordingly. Signed-off-by: Shereen Haj <[email protected]> (cherry picked from commit 558833b)
1 parent ce43486 commit 032e581

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

internal/controller/numaresourcesscheduler_controller.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,11 @@ func (r *NUMAResourcesSchedulerReconciler) Reconcile(ctx context.Context, req ct
112112
return ctrl.Result{}, err
113113
}
114114

115+
initialStatus := *instance.Status.DeepCopy()
116+
115117
if req.Name != objectnames.DefaultNUMAResourcesSchedulerCrName {
116118
message := fmt.Sprintf("incorrect NUMAResourcesScheduler resource name: %s", instance.Name)
117-
return ctrl.Result{}, r.updateStatus(ctx, instance, status.ConditionDegraded, status.ConditionTypeIncorrectNUMAResourcesSchedulerResourceName, message)
119+
return ctrl.Result{}, r.updateStatus(ctx, initialStatus, instance, status.ConditionDegraded, status.ConditionTypeIncorrectNUMAResourcesSchedulerResourceName, message)
118120
}
119121

120122
if annotations.IsPauseReconciliationEnabled(instance.Annotations) {
@@ -123,7 +125,7 @@ func (r *NUMAResourcesSchedulerReconciler) Reconcile(ctx context.Context, req ct
123125
}
124126

125127
result, condition, err := r.reconcileResource(ctx, instance)
126-
if err := r.updateStatus(ctx, instance, condition, status.ReasonFromError(err), status.MessageFromError(err)); err != nil {
128+
if err := r.updateStatus(ctx, initialStatus, instance, condition, status.ReasonFromError(err), status.MessageFromError(err)); err != nil {
127129
klog.InfoS("Failed to update numaresourcesscheduler status", "Desired condition", condition, "error", err)
128130
}
129131

@@ -287,8 +289,15 @@ func platformNormalize(spec *nropv1.NUMAResourcesSchedulerSpec, platInfo Platfor
287289
klog.V(4).InfoS("SchedulerInformer default is overridden", "Platform", platInfo.Platform, "PlatformVersion", platInfo.Version.String(), "SchedulerInformer", &spec.SchedulerInformer)
288290
}
289291
}
290-
func (r *NUMAResourcesSchedulerReconciler) updateStatus(ctx context.Context, sched *nropv1.NUMAResourcesScheduler, condition string, reason string, message string) error {
291-
sched.Status.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
292+
func (r *NUMAResourcesSchedulerReconciler) updateStatus(ctx context.Context, initialStatus nropv1.NUMAResourcesSchedulerStatus, sched *nropv1.NUMAResourcesScheduler, condition string, reason string, message string) error {
293+
updatedStatus := *sched.Status.DeepCopy()
294+
295+
updatedStatus.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
296+
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, updatedStatus) {
297+
return nil
298+
}
299+
300+
sched.Status.Conditions = updatedStatus.Conditions
292301
if err := r.Client.Status().Update(ctx, sched); err != nil {
293302
return fmt.Errorf("could not update status for object %s: %w", client.ObjectKeyFromObject(sched), err)
294303
}

internal/controller/numaresourcesscheduler_controller_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,6 @@ var _ = ginkgo.Describe("Test scheduler spec platformNormalize", func() {
825825
})
826826

827827
ginkgo.It("should not override default informer if kubelet is not fixed - version is less than first supported (zstream)", func() {
828-
// this is only for testing purposes as there is plan to backport the fix to older minor versions
829-
// will need to remove this test if the fix is supported starting the first zstream of the release
830828
v, _ := platform.ParseVersion("4.19.8")
831829
spec := nropv1.NUMAResourcesSchedulerSpec{}
832830
platformNormalize(&spec, PlatformInfo{Platform: platform.OpenShift, Version: v})

pkg/status/status.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ func IsUpdatedNUMAResourcesOperator(oldStatus, newStatus *nropv1.NUMAResourcesOp
5858
return !reflect.DeepEqual(os, ns)
5959
}
6060

61+
func NUMAResourcesSchedulerNeedsUpdate(oldStatus, newStatus nropv1.NUMAResourcesSchedulerStatus) bool {
62+
os := oldStatus.DeepCopy()
63+
ns := newStatus.DeepCopy()
64+
65+
resetIncomparableConditionFields(os.Conditions)
66+
resetIncomparableConditionFields(ns.Conditions)
67+
68+
return !reflect.DeepEqual(os, ns)
69+
}
70+
6171
// UpdateConditions compute new conditions based on arguments, and then compare with given current conditions.
6272
// Returns the conditions to use, either current or newly computed, and a boolean flag which is `true` if conditions need
6373
// update - so if they are updated since the current conditions.

pkg/status/status_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525

2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/client-go/kubernetes/scheme"
28+
"k8s.io/utils/ptr"
29+
2830
"sigs.k8s.io/controller-runtime/pkg/client"
2931
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3032

@@ -191,6 +193,58 @@ func TestIsUpdatedNUMAResourcesOperator(t *testing.T) {
191193
}
192194
}
193195

196+
func TestNUMAResourcesSchedulerNeedsUpdate(t *testing.T) {
197+
type testCase struct {
198+
name string
199+
oldStatus nropv1.NUMAResourcesSchedulerStatus
200+
updaterFunc func(*nropv1.NUMAResourcesSchedulerStatus)
201+
expectedUpdated bool
202+
}
203+
testCases := []testCase{
204+
{
205+
name: "empty status, no change",
206+
oldStatus: nropv1.NUMAResourcesSchedulerStatus{},
207+
updaterFunc: func(st *nropv1.NUMAResourcesSchedulerStatus) {},
208+
expectedUpdated: false,
209+
},
210+
{
211+
name: "status, conditions, updated only time",
212+
oldStatus: nropv1.NUMAResourcesSchedulerStatus{
213+
Conditions: NewConditions(ConditionAvailable, "test all good", "testing info"),
214+
},
215+
updaterFunc: func(st *nropv1.NUMAResourcesSchedulerStatus) {
216+
time.Sleep(42 * time.Millisecond) // make sure the timestamp changed
217+
st.Conditions = NewConditions(ConditionAvailable, "test all good", "testing info")
218+
},
219+
expectedUpdated: false,
220+
},
221+
{
222+
name: "status, conditions, updated only time, other fields changed",
223+
oldStatus: nropv1.NUMAResourcesSchedulerStatus{
224+
Conditions: NewConditions(ConditionAvailable, "test all good", "testing info"),
225+
},
226+
updaterFunc: func(st *nropv1.NUMAResourcesSchedulerStatus) {
227+
time.Sleep(42 * time.Millisecond) // make sure the timestamp changed
228+
st.Conditions = NewConditions(ConditionAvailable, "test all good", "testing info")
229+
st.CacheResyncPeriod = ptr.To(metav1.Duration{Duration: 42 * time.Second})
230+
},
231+
expectedUpdated: true,
232+
},
233+
}
234+
235+
for _, tc := range testCases {
236+
t.Run(tc.name, func(t *testing.T) {
237+
oldStatus := *tc.oldStatus.DeepCopy()
238+
newStatus := *tc.oldStatus.DeepCopy()
239+
tc.updaterFunc(&newStatus)
240+
got := NUMAResourcesSchedulerNeedsUpdate(oldStatus, newStatus)
241+
if got != tc.expectedUpdated {
242+
t.Errorf("isUpdated %v expected %v", got, tc.expectedUpdated)
243+
}
244+
})
245+
}
246+
}
247+
194248
func TestReasonFromError(t *testing.T) {
195249
type testCase struct {
196250
name string

0 commit comments

Comments
 (0)