Skip to content

Commit 4d8d5dc

Browse files
committed
fix(controller): preserve shared Skyhook cordons
Signed-off-by: Minh Vu <vuhoangminh97@gmail.com>
1 parent 98fe42d commit 4d8d5dc

2 files changed

Lines changed: 118 additions & 6 deletions

File tree

operator/internal/wrapper/node.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,14 @@ func (node *skyhookNode) HasSkyhookAnnotations() bool {
467467

468468
// Cordon marks the node unschedulable and records the cordon in annotations for this Skyhook.
469469
func (node *skyhookNode) Cordon() {
470-
_, ok := node.Annotations[fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, node.skyhookName)]
470+
if node.Annotations == nil {
471+
node.Annotations = make(map[string]string)
472+
}
473+
474+
_, ok := node.Annotations[cordonAnnotationKey(node.skyhookName)]
471475
if !node.Spec.Unschedulable || !ok {
472476
node.Spec.Unschedulable = true
473-
node.Annotations[fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, node.skyhookName)] = "true"
477+
node.Annotations[cordonAnnotationKey(node.skyhookName)] = "true"
474478
node.updated = true
475479
}
476480
}
@@ -479,14 +483,32 @@ func (node *skyhookNode) Cordon() {
479483
func (node *skyhookNode) Uncordon() {
480484

481485
// if we hold a cordon remove it, also we dont want to remove a cordon if we dont have one...
482-
_, ok := node.Annotations[fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, node.skyhookName)]
486+
_, ok := node.Annotations[cordonAnnotationKey(node.skyhookName)]
483487
if ok {
484-
node.Spec.Unschedulable = false
485-
delete(node.Annotations, fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, node.skyhookName))
488+
delete(node.Annotations, cordonAnnotationKey(node.skyhookName))
489+
// Multiple Skyhooks can cordon the same node; only mark it schedulable
490+
// after every Skyhook-owned cordon has been released.
491+
if !hasSkyhookCordon(node.Annotations) {
492+
node.Spec.Unschedulable = false
493+
}
486494
node.updated = true
487495
}
488496
}
489497

498+
func cordonAnnotationKey(skyhookName string) string {
499+
return fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, skyhookName)
500+
}
501+
502+
func hasSkyhookCordon(annotations map[string]string) bool {
503+
prefix := fmt.Sprintf("%s/cordon_", v1alpha1.METADATA_PREFIX)
504+
for key := range annotations {
505+
if strings.HasPrefix(key, prefix) {
506+
return true
507+
}
508+
}
509+
return false
510+
}
511+
490512
// Reset clears Skyhook-related state and annotations so the node can be reconfigured from scratch.
491513
func (node *skyhookNode) Reset() {
492514

@@ -495,7 +517,7 @@ func (node *skyhookNode) Reset() {
495517
node.skyhook.Status.Status = v1alpha1.StatusUnknown
496518
node.skyhook.Updated = true
497519

498-
delete(node.Annotations, fmt.Sprintf("%s/cordon_%s", v1alpha1.METADATA_PREFIX, node.skyhookName))
520+
delete(node.Annotations, cordonAnnotationKey(node.skyhookName))
499521
delete(node.Annotations, fmt.Sprintf("%s/nodeState_%s", v1alpha1.METADATA_PREFIX, node.skyhookName))
500522
delete(node.Annotations, fmt.Sprintf("%s/status_%s", v1alpha1.METADATA_PREFIX, node.skyhookName))
501523

operator/internal/wrapper/node_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,96 @@ var _ = Describe("SkyhookNode", func() {
178178
})
179179
})
180180

181+
Context("Cordon", func() {
182+
It("should initialize annotations if the node has none", func() {
183+
myCordonKey := cordonAnnotationKey("my-skyhook")
184+
node := &corev1.Node{
185+
ObjectMeta: metav1.ObjectMeta{
186+
Name: "test-node",
187+
},
188+
}
189+
190+
sn, err := NewSkyhookNodeOnly(node, "my-skyhook")
191+
Expect(err).ToNot(HaveOccurred())
192+
193+
sn.Cordon()
194+
195+
Expect(node.Spec.Unschedulable).To(BeTrue())
196+
Expect(node.Annotations).To(HaveKeyWithValue(myCordonKey, "true"))
197+
Expect(sn.Changed()).To(BeTrue())
198+
})
199+
})
200+
201+
Context("Uncordon", func() {
202+
myCordonKey := cordonAnnotationKey("my-skyhook")
203+
otherCordonKey := cordonAnnotationKey("other-skyhook")
204+
205+
It("should make the node schedulable if this Skyhook owns the only cordon", func() {
206+
node := &corev1.Node{
207+
ObjectMeta: metav1.ObjectMeta{
208+
Name: "test-node",
209+
Annotations: map[string]string{
210+
myCordonKey: "true",
211+
},
212+
},
213+
Spec: corev1.NodeSpec{Unschedulable: true},
214+
}
215+
216+
sn, err := NewSkyhookNodeOnly(node, "my-skyhook")
217+
Expect(err).ToNot(HaveOccurred())
218+
219+
sn.Uncordon()
220+
221+
Expect(node.Spec.Unschedulable).To(BeFalse())
222+
Expect(node.Annotations).ToNot(HaveKey(myCordonKey))
223+
Expect(sn.Changed()).To(BeTrue())
224+
})
225+
226+
It("should keep the node unschedulable if another Skyhook still owns a cordon", func() {
227+
node := &corev1.Node{
228+
ObjectMeta: metav1.ObjectMeta{
229+
Name: "test-node",
230+
Annotations: map[string]string{
231+
myCordonKey: "true",
232+
otherCordonKey: "true",
233+
},
234+
},
235+
Spec: corev1.NodeSpec{Unschedulable: true},
236+
}
237+
238+
sn, err := NewSkyhookNodeOnly(node, "my-skyhook")
239+
Expect(err).ToNot(HaveOccurred())
240+
241+
sn.Uncordon()
242+
243+
Expect(node.Spec.Unschedulable).To(BeTrue())
244+
Expect(node.Annotations).ToNot(HaveKey(myCordonKey))
245+
Expect(node.Annotations).To(HaveKeyWithValue(otherCordonKey, "true"))
246+
Expect(sn.Changed()).To(BeTrue())
247+
})
248+
249+
It("should not change the node if this Skyhook does not own a cordon", func() {
250+
node := &corev1.Node{
251+
ObjectMeta: metav1.ObjectMeta{
252+
Name: "test-node",
253+
Annotations: map[string]string{
254+
otherCordonKey: "true",
255+
},
256+
},
257+
Spec: corev1.NodeSpec{Unschedulable: true},
258+
}
259+
260+
sn, err := NewSkyhookNodeOnly(node, "my-skyhook")
261+
Expect(err).ToNot(HaveOccurred())
262+
263+
sn.Uncordon()
264+
265+
Expect(node.Spec.Unschedulable).To(BeTrue())
266+
Expect(node.Annotations).To(HaveKeyWithValue(otherCordonKey, "true"))
267+
Expect(sn.Changed()).To(BeFalse())
268+
})
269+
})
270+
181271
Context("CleanupSCRMetadata", func() {
182272
It("should remove matching keys and preserve others", func() {
183273
node := &corev1.Node{

0 commit comments

Comments
 (0)