Skip to content

Commit 09d76b9

Browse files
committed
controller: sched: report DedicatedInformerActive behavior
We want to be able to see the informer mode of the scheduler as a preparation step for having the informer default change according to the kubelet version. This commit enables reflecting the informer value (default or configured) as part of the status conditions which is less direct than reporting it in spec and is valid. Signed-off-by: Shereen Haj <[email protected]>
1 parent 4fb50a8 commit 09d76b9

File tree

4 files changed

+347
-7
lines changed

4 files changed

+347
-7
lines changed

internal/controller/numaresourcesscheduler_controller.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ func (r *NUMAResourcesSchedulerReconciler) syncNUMASchedulerResources(ctx contex
311311
Duration: cacheResyncPeriod,
312312
}
313313

314+
informerCondition := buildDedicatedInformerCondition(*instance, schedSpec)
315+
schedStatus.Conditions = status.GetUpdatedSchedulerConditions(schedStatus.Conditions, informerCondition)
316+
314317
r.SchedulerManifests.Deployment.Spec.Replicas = schedSpec.Replicas
315318
klog.V(4).InfoS("using scheduler replicas", "replicas", *r.SchedulerManifests.Deployment.Spec.Replicas)
316319
// TODO: if replicas doesn't make sense (autodetect disabled and user set impossible value) then we
@@ -377,15 +380,39 @@ func platformNormalize(spec *nropv1.NUMAResourcesSchedulerSpec, platInfo Platfor
377380
klog.V(4).InfoS("SchedulerInformer default is overridden", "Platform", platInfo.Platform, "PlatformVersion", platInfo.Version.String(), "SchedulerInformer", &spec.SchedulerInformer)
378381
}
379382
}
383+
384+
func buildDedicatedInformerCondition(instance nropv1.NUMAResourcesScheduler, normalized nropv1.NUMAResourcesSchedulerSpec) metav1.Condition {
385+
condition := metav1.Condition{
386+
Type: status.ConditionDedicatedInformerActive,
387+
Status: metav1.ConditionTrue,
388+
ObservedGeneration: instance.ObjectMeta.Generation,
389+
Reason: status.ConditionDedicatedInformerActive,
390+
}
391+
392+
if *normalized.SchedulerInformer == nropv1.SchedulerInformerShared {
393+
condition.Status = metav1.ConditionFalse
394+
}
395+
396+
return condition
397+
}
398+
380399
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()
400+
c := metav1.Condition{
401+
Type: condition,
402+
Status: metav1.ConditionTrue,
403+
Reason: reason,
404+
Message: message,
405+
}
406+
sched.Status.Conditions = status.GetUpdatedSchedulerConditions(sched.Status.Conditions, c)
382407

383-
updatedStatus.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
384-
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, updatedStatus) {
408+
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, sched.Status) {
385409
return nil
386410
}
387411

388-
sched.Status.Conditions = updatedStatus.Conditions
412+
if status.EqualConditions(initialStatus.Conditions, sched.Status.Conditions) {
413+
sched.Status.Conditions = initialStatus.Conditions
414+
}
415+
389416
if err := r.Client.Status().Update(ctx, sched); err != nil {
390417
return fmt.Errorf("could not update status for object %s: %w", client.ObjectKeyFromObject(sched), err)
391418
}

internal/controller/numaresourcesscheduler_controller_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,67 @@ var _ = Describe("Test NUMAResourcesScheduler Reconcile", func() {
222222
Expect(nrs.Status.CacheResyncPeriod.Seconds()).To(Equal(resyncPeriod.Seconds()))
223223
})
224224

225+
Context("should reflect DedicatedInformerActive in status conditions", func() {
226+
It("with default values", func() {
227+
key := client.ObjectKeyFromObject(nrs)
228+
_, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key})
229+
Expect(err).ToNot(HaveOccurred())
230+
231+
Expect(reconciler.Client.Get(context.TODO(), key, nrs)).To(Succeed())
232+
233+
c := getConditionByType(nrs.Status.Conditions, status.ConditionDedicatedInformerActive)
234+
235+
Expect(c).ToNot(BeNil())
236+
Expect(c.Status).To(Equal(metav1.ConditionTrue))
237+
})
238+
239+
It("with updated values - explicitly configured to Dedicated", func() {
240+
nrs := nrs.DeepCopy()
241+
nrs.Spec.SchedulerInformer = ptr.To(nropv1.SchedulerInformerDedicated)
242+
243+
Eventually(func() bool {
244+
if err := reconciler.Client.Update(context.TODO(), nrs); err != nil {
245+
klog.Warningf("failed to update the scheduler object; err: %v", err)
246+
return false
247+
}
248+
return true
249+
}, 30*time.Second, 5*time.Second).Should(BeTrue())
250+
251+
key := client.ObjectKeyFromObject(nrs)
252+
_, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key})
253+
Expect(err).ToNot(HaveOccurred())
254+
Expect(reconciler.Client.Get(context.TODO(), key, nrs)).To(Succeed())
255+
256+
c := getConditionByType(nrs.Status.Conditions, status.ConditionDedicatedInformerActive)
257+
258+
Expect(c).ToNot(BeNil())
259+
Expect(c.Status).To(Equal(metav1.ConditionTrue))
260+
})
261+
262+
It("with updated values - explicitly configured to Shared", func() {
263+
nrs := nrs.DeepCopy()
264+
nrs.Spec.SchedulerInformer = ptr.To(nropv1.SchedulerInformerShared)
265+
266+
Eventually(func() bool {
267+
if err := reconciler.Client.Update(context.TODO(), nrs); err != nil {
268+
klog.Warningf("failed to update the scheduler object; err: %v", err)
269+
return false
270+
}
271+
return true
272+
}, 30*time.Second, 5*time.Second).Should(BeTrue())
273+
274+
key := client.ObjectKeyFromObject(nrs)
275+
_, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key})
276+
Expect(err).ToNot(HaveOccurred())
277+
Expect(reconciler.Client.Get(context.TODO(), key, nrs)).To(Succeed())
278+
279+
c := getConditionByType(nrs.Status.Conditions, status.ConditionDedicatedInformerActive)
280+
281+
Expect(c).ToNot(BeNil())
282+
Expect(c.Status).To(Equal(metav1.ConditionFalse))
283+
})
284+
})
285+
225286
It("should have the correct priority class", func() {
226287
key := client.ObjectKeyFromObject(nrs)
227288
_, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key})
@@ -749,6 +810,17 @@ var _ = Describe("Test NUMAResourcesScheduler Reconcile", func() {
749810
Expect(err).ToNot(HaveOccurred())
750811

751812
expectCacheParams(reconciler.Client, depmanifests.CacheResyncAutodetect, depmanifests.CacheResyncOnlyExclusiveResources, expectedInformer)
813+
814+
expectedDedicatedActiveStatus := metav1.ConditionTrue
815+
if expectedInformer == depmanifests.CacheInformerShared {
816+
expectedDedicatedActiveStatus = metav1.ConditionFalse
817+
}
818+
819+
Expect(reconciler.Client.Get(context.TODO(), key, nrs)).To(Succeed())
820+
c := getConditionByType(nrs.Status.Conditions, status.ConditionDedicatedInformerActive)
821+
822+
Expect(c).ToNot(BeNil())
823+
Expect(c.Status).To(Equal(expectedDedicatedActiveStatus))
752824
},
753825
Entry("with fixed Openshift the default informer is Shared", PlatformInfo{
754826
Platform: platform.OpenShift,

pkg/status/status.go

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ const (
3434
ConditionUpgradeable = "Upgradeable"
3535
)
3636

37+
const (
38+
ConditionDedicatedInformerActive = "DedicatedInformerActive"
39+
)
40+
3741
// TODO: are we duping these?
3842
const (
3943
ReasonAsExpected = "AsExpected"
@@ -68,14 +72,24 @@ func NUMAResourcesSchedulerNeedsUpdate(oldStatus, newStatus nropv1.NUMAResources
6872
return !reflect.DeepEqual(os, ns)
6973
}
7074

75+
func EqualConditions(current, updated []metav1.Condition) bool {
76+
c := CloneConditions(current)
77+
u := CloneConditions(updated)
78+
79+
resetIncomparableConditionFields(c)
80+
resetIncomparableConditionFields(u)
81+
82+
return reflect.DeepEqual(c, u)
83+
}
84+
7185
// UpdateConditions compute new conditions based on arguments, and then compare with given current conditions.
7286
// Returns the conditions to use, either current or newly computed, and a boolean flag which is `true` if conditions need
7387
// update - so if they are updated since the current conditions.
7488
func UpdateConditions(currentConditions []metav1.Condition, condition string, reason string, message string) ([]metav1.Condition, bool) {
7589
conditions := NewConditions(condition, reason, message)
7690

77-
cond := clone(conditions)
78-
curCond := clone(currentConditions)
91+
cond := CloneConditions(conditions)
92+
curCond := CloneConditions(currentConditions)
7993

8094
resetIncomparableConditionFields(cond)
8195
resetIncomparableConditionFields(curCond)
@@ -144,6 +158,42 @@ func newBaseConditions() []metav1.Condition {
144158
}
145159
}
146160

161+
func NewNUMAResourcesSchedulerBaseConditions() []metav1.Condition {
162+
now := time.Now()
163+
return []metav1.Condition{
164+
{
165+
Type: ConditionAvailable,
166+
Status: metav1.ConditionFalse,
167+
LastTransitionTime: metav1.Time{Time: now},
168+
Reason: ConditionAvailable,
169+
},
170+
{
171+
Type: ConditionUpgradeable,
172+
Status: metav1.ConditionFalse,
173+
LastTransitionTime: metav1.Time{Time: now},
174+
Reason: ConditionUpgradeable,
175+
},
176+
{
177+
Type: ConditionProgressing,
178+
Status: metav1.ConditionFalse,
179+
LastTransitionTime: metav1.Time{Time: now},
180+
Reason: ConditionProgressing,
181+
},
182+
{
183+
Type: ConditionDegraded,
184+
Status: metav1.ConditionFalse,
185+
LastTransitionTime: metav1.Time{Time: now},
186+
Reason: ConditionDegraded,
187+
},
188+
{
189+
Type: ConditionDedicatedInformerActive,
190+
Status: metav1.ConditionUnknown,
191+
LastTransitionTime: metav1.Time{Time: now},
192+
Reason: ConditionDedicatedInformerActive,
193+
},
194+
}
195+
}
196+
147197
func ReasonFromError(err error) string {
148198
if err == nil {
149199
return ReasonAsExpected
@@ -169,8 +219,37 @@ func resetIncomparableConditionFields(conditions []metav1.Condition) {
169219
}
170220
}
171221

172-
func clone(conditions []metav1.Condition) []metav1.Condition {
222+
func CloneConditions(conditions []metav1.Condition) []metav1.Condition {
173223
var c = make([]metav1.Condition, len(conditions))
174224
copy(c, conditions)
175225
return c
176226
}
227+
228+
func GetUpdatedSchedulerConditions(conditions []metav1.Condition, condition metav1.Condition) []metav1.Condition {
229+
updatedConditions := NewNUMAResourcesSchedulerBaseConditions()
230+
if len(conditions) != 0 {
231+
updatedConditions = CloneConditions(conditions)
232+
}
233+
234+
now := time.Now()
235+
for idx, cond := range updatedConditions {
236+
if cond.Type == condition.Type {
237+
updatedConditions[idx] = condition
238+
updatedConditions[idx].LastTransitionTime = metav1.Time{Time: now}
239+
break
240+
}
241+
}
242+
243+
if condition.Type == ConditionAvailable {
244+
for idx, cond := range updatedConditions {
245+
if cond.Type == ConditionUpgradeable {
246+
updatedConditions[idx].Status = condition.Status
247+
updatedConditions[idx].LastTransitionTime = metav1.Time{Time: now}
248+
249+
break
250+
}
251+
}
252+
}
253+
254+
return updatedConditions
255+
}

0 commit comments

Comments
 (0)