Skip to content

Commit 2a34cb8

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) (cherry picked from commit 032e581)
1 parent 122a13b commit 2a34cb8

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

controllers/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
}

controllers/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.18.8")
831829
spec := nropv1.NUMAResourcesSchedulerSpec{}
832830
platformNormalize(&spec, PlatformInfo{Platform: platform.OpenShift, Version: v})

pkg/status/status.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package status
1818

1919
import (
2020
"errors"
21+
"reflect"
2122
"time"
2223

2324
"github.com/google/go-cmp/cmp"
@@ -59,6 +60,16 @@ func IsUpdatedNUMAResourcesOperator(oldStatus, newStatus *nropv1.NUMAResourcesOp
5960
return !cmp.Equal(newStatus, oldStatus, options...)
6061
}
6162

63+
func NUMAResourcesSchedulerNeedsUpdate(oldStatus, newStatus nropv1.NUMAResourcesSchedulerStatus) bool {
64+
os := oldStatus.DeepCopy()
65+
ns := newStatus.DeepCopy()
66+
67+
resetIncomparableConditionFields(os.Conditions)
68+
resetIncomparableConditionFields(ns.Conditions)
69+
70+
return !reflect.DeepEqual(os, ns)
71+
}
72+
6273
// UpdateConditions compute new conditions based on arguments, and then compare with given current conditions.
6374
// Returns the conditions to use, either current or newly computed, and a boolean flag which is `true` if conditions need
6475
// 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

@@ -201,6 +203,58 @@ func TestIsUpdatedNUMAResourcesOperator(t *testing.T) {
201203
}
202204
}
203205

206+
func TestNUMAResourcesSchedulerNeedsUpdate(t *testing.T) {
207+
type testCase struct {
208+
name string
209+
oldStatus nropv1.NUMAResourcesSchedulerStatus
210+
updaterFunc func(*nropv1.NUMAResourcesSchedulerStatus)
211+
expectedUpdated bool
212+
}
213+
testCases := []testCase{
214+
{
215+
name: "empty status, no change",
216+
oldStatus: nropv1.NUMAResourcesSchedulerStatus{},
217+
updaterFunc: func(st *nropv1.NUMAResourcesSchedulerStatus) {},
218+
expectedUpdated: false,
219+
},
220+
{
221+
name: "status, conditions, updated only time",
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+
},
229+
expectedUpdated: false,
230+
},
231+
{
232+
name: "status, conditions, updated only time, other fields changed",
233+
oldStatus: nropv1.NUMAResourcesSchedulerStatus{
234+
Conditions: NewConditions(ConditionAvailable, "test all good", "testing info"),
235+
},
236+
updaterFunc: func(st *nropv1.NUMAResourcesSchedulerStatus) {
237+
time.Sleep(42 * time.Millisecond) // make sure the timestamp changed
238+
st.Conditions = NewConditions(ConditionAvailable, "test all good", "testing info")
239+
st.CacheResyncPeriod = ptr.To(metav1.Duration{Duration: 42 * time.Second})
240+
},
241+
expectedUpdated: true,
242+
},
243+
}
244+
245+
for _, tc := range testCases {
246+
t.Run(tc.name, func(t *testing.T) {
247+
oldStatus := *tc.oldStatus.DeepCopy()
248+
newStatus := *tc.oldStatus.DeepCopy()
249+
tc.updaterFunc(&newStatus)
250+
got := NUMAResourcesSchedulerNeedsUpdate(oldStatus, newStatus)
251+
if got != tc.expectedUpdated {
252+
t.Errorf("isUpdated %v expected %v", got, tc.expectedUpdated)
253+
}
254+
})
255+
}
256+
}
257+
204258
func TestReasonFromError(t *testing.T) {
205259
type testCase struct {
206260
name string

0 commit comments

Comments
 (0)