Skip to content

Commit 79be8cb

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]> (cherry picked from commit 09d76b9)
1 parent 032e581 commit 79be8cb

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
@@ -224,6 +224,9 @@ func (r *NUMAResourcesSchedulerReconciler) syncNUMASchedulerResources(ctx contex
224224
Duration: cacheResyncPeriod,
225225
}
226226

227+
informerCondition := buildDedicatedInformerCondition(*instance, schedSpec)
228+
schedStatus.Conditions = status.GetUpdatedSchedulerConditions(schedStatus.Conditions, informerCondition)
229+
227230
r.SchedulerManifests.Deployment.Spec.Replicas = r.computeSchedulerReplicas(schedSpec)
228231
klog.V(4).InfoS("using scheduler replicas", "replicas", *r.SchedulerManifests.Deployment.Spec.Replicas)
229232
// TODO: if replicas doesn't make sense (autodetect disabled and user set impossible value) then we
@@ -289,15 +292,39 @@ func platformNormalize(spec *nropv1.NUMAResourcesSchedulerSpec, platInfo Platfor
289292
klog.V(4).InfoS("SchedulerInformer default is overridden", "Platform", platInfo.Platform, "PlatformVersion", platInfo.Version.String(), "SchedulerInformer", &spec.SchedulerInformer)
290293
}
291294
}
295+
296+
func buildDedicatedInformerCondition(instance nropv1.NUMAResourcesScheduler, normalized nropv1.NUMAResourcesSchedulerSpec) metav1.Condition {
297+
condition := metav1.Condition{
298+
Type: status.ConditionDedicatedInformerActive,
299+
Status: metav1.ConditionTrue,
300+
ObservedGeneration: instance.ObjectMeta.Generation,
301+
Reason: status.ConditionDedicatedInformerActive,
302+
}
303+
304+
if *normalized.SchedulerInformer == nropv1.SchedulerInformerShared {
305+
condition.Status = metav1.ConditionFalse
306+
}
307+
308+
return condition
309+
}
310+
292311
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()
312+
c := metav1.Condition{
313+
Type: condition,
314+
Status: metav1.ConditionTrue,
315+
Reason: reason,
316+
Message: message,
317+
}
318+
sched.Status.Conditions = status.GetUpdatedSchedulerConditions(sched.Status.Conditions, c)
294319

295-
updatedStatus.Conditions, _ = status.UpdateConditions(sched.Status.Conditions, condition, reason, message)
296-
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, updatedStatus) {
320+
if !status.NUMAResourcesSchedulerNeedsUpdate(initialStatus, sched.Status) {
297321
return nil
298322
}
299323

300-
sched.Status.Conditions = updatedStatus.Conditions
324+
if status.EqualConditions(initialStatus.Conditions, sched.Status.Conditions) {
325+
sched.Status.Conditions = initialStatus.Conditions
326+
}
327+
301328
if err := r.Client.Status().Update(ctx, sched); err != nil {
302329
return fmt.Errorf("could not update status for object %s: %w", client.ObjectKeyFromObject(sched), err)
303330
}

internal/controller/numaresourcesscheduler_controller_test.go

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

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

722783
expectCacheParams(reconciler.Client, depmanifests.CacheResyncAutodetect, depmanifests.CacheResyncOnlyExclusiveResources, expectedInformer)
784+
785+
expectedDedicatedActiveStatus := metav1.ConditionTrue
786+
if expectedInformer == depmanifests.CacheInformerShared {
787+
expectedDedicatedActiveStatus = metav1.ConditionFalse
788+
}
789+
790+
gomega.Expect(reconciler.Client.Get(context.TODO(), key, nrs)).To(gomega.Succeed())
791+
c := getConditionByType(nrs.Status.Conditions, status.ConditionDedicatedInformerActive)
792+
793+
gomega.Expect(c).ToNot(gomega.BeNil())
794+
gomega.Expect(c.Status).To(gomega.Equal(expectedDedicatedActiveStatus))
723795
},
724796
ginkgo.Entry("with fixed Openshift the default informer is Shared", PlatformInfo{
725797
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)