Skip to content

Commit 558833b

Browse files
committed
controller: sched: update status only if needed
So far updatinf the status was done in every reconcilation iteration even if the spec fields reflected the same values. This commits 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]>
1 parent 86f9384 commit 558833b

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

internal/controller/numaresourcesscheduler_controller.go

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

125+
initialStatus := *instance.Status.DeepCopy()
126+
125127
if req.Name != objectnames.DefaultNUMAResourcesSchedulerCrName {
126128
message := fmt.Sprintf("incorrect NUMAResourcesScheduler resource name: %s", instance.Name)
127-
return ctrl.Result{}, r.updateStatus(ctx, instance, status.ConditionDegraded, status.ConditionTypeIncorrectNUMAResourcesSchedulerResourceName, message)
129+
return ctrl.Result{}, r.updateStatus(ctx, initialStatus, instance, status.ConditionDegraded, status.ConditionTypeIncorrectNUMAResourcesSchedulerResourceName, message)
128130
}
129131

130132
if annotations.IsPauseReconciliationEnabled(instance.Annotations) {
@@ -133,7 +135,7 @@ func (r *NUMAResourcesSchedulerReconciler) Reconcile(ctx context.Context, req ct
133135
}
134136

135137
result, condition, err := r.reconcileResource(ctx, instance)
136-
if err := r.updateStatus(ctx, instance, condition, status.ReasonFromError(err), status.MessageFromError(err)); err != nil {
138+
if err := r.updateStatus(ctx, initialStatus, instance, condition, status.ReasonFromError(err), status.MessageFromError(err)); err != nil {
137139
klog.InfoS("Failed to update numaresourcesscheduler status", "Desired condition", condition, "error", err)
138140
}
139141

@@ -375,8 +377,15 @@ func platformNormalize(spec *nropv1.NUMAResourcesSchedulerSpec, platInfo Platfor
375377
klog.V(4).InfoS("SchedulerInformer default is overridden", "Platform", platInfo.Platform, "PlatformVersion", platInfo.Version.String(), "SchedulerInformer", &spec.SchedulerInformer)
376378
}
377379
}
378-
func (r *NUMAResourcesSchedulerReconciler) updateStatus(ctx context.Context, sched *nropv1.NUMAResourcesScheduler, condition string, reason string, message string) error {
379-
sched.Status.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
380+
func (r *NUMAResourcesSchedulerReconciler) updateStatus(ctx context.Context, initialStatus nropv1.NUMAResourcesSchedulerStatus, sched *nropv1.NUMAResourcesScheduler, condition string, reason string, message string) error {
381+
updatedStatus := *sched.Status.DeepCopy()
382+
383+
updatedStatus.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
384+
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, updatedStatus) {
385+
return nil
386+
}
387+
388+
sched.Status.Conditions = updatedStatus.Conditions
380389
if err := r.Client.Status().Update(ctx, sched); err != nil {
381390
return fmt.Errorf("could not update status for object %s: %w", client.ObjectKeyFromObject(sched), err)
382391
}

pkg/status/status.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ func NUMAResourceOperatorNeedsUpdate(oldStatus, newStatus *nropv1.NUMAResourcesO
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: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/client-go/kubernetes/scheme"
28+
"k8s.io/utils/ptr"
2829

2930
"sigs.k8s.io/controller-runtime/pkg/client"
3031
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -191,6 +192,58 @@ func TestNUMAResourceOperatorNeedsUpdate(t *testing.T) {
191192
}
192193
}
193194

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

0 commit comments

Comments
 (0)